mac80211: fix a few work bugs
[linux-2.6-block.git] / drivers / net / wireless / b43 / phy_lp.c
CommitLineData
e63e4363
MB
1/*
2
3 Broadcom B43 wireless driver
0136e51e 4 IEEE 802.11a/g LP-PHY driver
e63e4363 5
6c1bb927 6 Copyright (c) 2008-2009 Michael Buesch <mb@bu3sch.de>
0136e51e 7 Copyright (c) 2009 Gábor Stefanik <netrolller.3d@gmail.com>
e63e4363
MB
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23
24*/
25
26#include "b43.h"
ce1a9ee3 27#include "main.h"
e63e4363
MB
28#include "phy_lp.h"
29#include "phy_common.h"
6c1bb927 30#include "tables_lpphy.h"
e63e4363
MB
31
32
588f8377
GS
33static inline u16 channel2freq_lp(u8 channel)
34{
35 if (channel < 14)
36 return (2407 + 5 * channel);
37 else if (channel == 14)
38 return 2484;
39 else if (channel < 184)
40 return (5000 + 5 * channel);
41 else
42 return (4000 + 5 * channel);
43}
44
45static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev)
46{
47 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
68ec5329 48 return 1;
588f8377
GS
49 return 36;
50}
51
e63e4363
MB
52static int b43_lpphy_op_allocate(struct b43_wldev *dev)
53{
54 struct b43_phy_lp *lpphy;
55
56 lpphy = kzalloc(sizeof(*lpphy), GFP_KERNEL);
57 if (!lpphy)
58 return -ENOMEM;
59 dev->phy.lp = lpphy;
60
e63e4363
MB
61 return 0;
62}
63
fb11137a 64static void b43_lpphy_op_prepare_structs(struct b43_wldev *dev)
e63e4363 65{
fb11137a
MB
66 struct b43_phy *phy = &dev->phy;
67 struct b43_phy_lp *lpphy = phy->lp;
e63e4363 68
fb11137a 69 memset(lpphy, 0, sizeof(*lpphy));
2c0d6100 70 lpphy->antenna = B43_ANTENNA_DEFAULT;
e63e4363 71
fb11137a 72 //TODO
e63e4363
MB
73}
74
fb11137a 75static void b43_lpphy_op_free(struct b43_wldev *dev)
e63e4363
MB
76{
77 struct b43_phy_lp *lpphy = dev->phy.lp;
78
e63e4363
MB
79 kfree(lpphy);
80 dev->phy.lp = NULL;
81}
82
84ec167d
GS
83static void lpphy_read_band_sprom(struct b43_wldev *dev)
84{
85 struct b43_phy_lp *lpphy = dev->phy.lp;
86 struct ssb_bus *bus = dev->dev->bus;
87 u16 cckpo, maxpwr;
88 u32 ofdmpo;
89 int i;
90
91 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
92 lpphy->tx_isolation_med_band = bus->sprom.tri2g;
93 lpphy->bx_arch = bus->sprom.bxa2g;
94 lpphy->rx_pwr_offset = bus->sprom.rxpo2g;
95 lpphy->rssi_vf = bus->sprom.rssismf2g;
96 lpphy->rssi_vc = bus->sprom.rssismc2g;
97 lpphy->rssi_gs = bus->sprom.rssisav2g;
98 lpphy->txpa[0] = bus->sprom.pa0b0;
99 lpphy->txpa[1] = bus->sprom.pa0b1;
100 lpphy->txpa[2] = bus->sprom.pa0b2;
101 maxpwr = bus->sprom.maxpwr_bg;
102 lpphy->max_tx_pwr_med_band = maxpwr;
103 cckpo = bus->sprom.cck2gpo;
104 ofdmpo = bus->sprom.ofdm2gpo;
105 if (cckpo) {
106 for (i = 0; i < 4; i++) {
107 lpphy->tx_max_rate[i] =
108 maxpwr - (ofdmpo & 0xF) * 2;
109 ofdmpo >>= 4;
110 }
111 ofdmpo = bus->sprom.ofdm2gpo;
112 for (i = 4; i < 15; i++) {
113 lpphy->tx_max_rate[i] =
114 maxpwr - (ofdmpo & 0xF) * 2;
115 ofdmpo >>= 4;
116 }
117 } else {
118 ofdmpo &= 0xFF;
119 for (i = 0; i < 4; i++)
120 lpphy->tx_max_rate[i] = maxpwr;
121 for (i = 4; i < 15; i++)
122 lpphy->tx_max_rate[i] = maxpwr - ofdmpo;
123 }
124 } else { /* 5GHz */
125 lpphy->tx_isolation_low_band = bus->sprom.tri5gl;
126 lpphy->tx_isolation_med_band = bus->sprom.tri5g;
127 lpphy->tx_isolation_hi_band = bus->sprom.tri5gh;
128 lpphy->bx_arch = bus->sprom.bxa5g;
129 lpphy->rx_pwr_offset = bus->sprom.rxpo5g;
130 lpphy->rssi_vf = bus->sprom.rssismf5g;
131 lpphy->rssi_vc = bus->sprom.rssismc5g;
132 lpphy->rssi_gs = bus->sprom.rssisav5g;
133 lpphy->txpa[0] = bus->sprom.pa1b0;
134 lpphy->txpa[1] = bus->sprom.pa1b1;
135 lpphy->txpa[2] = bus->sprom.pa1b2;
136 lpphy->txpal[0] = bus->sprom.pa1lob0;
137 lpphy->txpal[1] = bus->sprom.pa1lob1;
138 lpphy->txpal[2] = bus->sprom.pa1lob2;
139 lpphy->txpah[0] = bus->sprom.pa1hib0;
140 lpphy->txpah[1] = bus->sprom.pa1hib1;
141 lpphy->txpah[2] = bus->sprom.pa1hib2;
142 maxpwr = bus->sprom.maxpwr_al;
143 ofdmpo = bus->sprom.ofdm5glpo;
144 lpphy->max_tx_pwr_low_band = maxpwr;
145 for (i = 4; i < 12; i++) {
146 lpphy->tx_max_ratel[i] = maxpwr - (ofdmpo & 0xF) * 2;
147 ofdmpo >>= 4;
148 }
149 maxpwr = bus->sprom.maxpwr_a;
150 ofdmpo = bus->sprom.ofdm5gpo;
151 lpphy->max_tx_pwr_med_band = maxpwr;
152 for (i = 4; i < 12; i++) {
153 lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2;
154 ofdmpo >>= 4;
155 }
156 maxpwr = bus->sprom.maxpwr_ah;
157 ofdmpo = bus->sprom.ofdm5ghpo;
158 lpphy->max_tx_pwr_hi_band = maxpwr;
159 for (i = 4; i < 12; i++) {
160 lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2;
161 ofdmpo >>= 4;
162 }
163 }
164}
165
588f8377 166static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq)
c65d6fbf
GS
167{
168 struct b43_phy_lp *lpphy = dev->phy.lp;
c65d6fbf
GS
169 u16 temp[3];
170 u16 isolation;
171
172 B43_WARN_ON(dev->phy.rev >= 2);
173
174 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
175 isolation = lpphy->tx_isolation_med_band;
176 else if (freq <= 5320)
177 isolation = lpphy->tx_isolation_low_band;
178 else if (freq <= 5700)
179 isolation = lpphy->tx_isolation_med_band;
180 else
181 isolation = lpphy->tx_isolation_hi_band;
182
183 temp[0] = ((isolation - 26) / 12) << 12;
184 temp[1] = temp[0] + 0x1000;
185 temp[2] = temp[0] + 0x2000;
186
c65d6fbf 187 b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp);
68ec5329 188 b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp);
c65d6fbf
GS
189}
190
a387cc7d
MB
191static void lpphy_table_init(struct b43_wldev *dev)
192{
588f8377
GS
193 u32 freq = channel2freq_lp(b43_lpphy_op_get_default_chan(dev));
194
c65d6fbf
GS
195 if (dev->phy.rev < 2)
196 lpphy_rev0_1_table_init(dev);
197 else
198 lpphy_rev2plus_table_init(dev);
199
200 lpphy_init_tx_gain_table(dev);
201
202 if (dev->phy.rev < 2)
588f8377 203 lpphy_adjust_gain_table(dev, freq);
a387cc7d
MB
204}
205
206static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
207{
738f0f43 208 struct ssb_bus *bus = dev->dev->bus;
96909e97 209 struct b43_phy_lp *lpphy = dev->phy.lp;
738f0f43
GS
210 u16 tmp, tmp2;
211
96909e97
GS
212 b43_phy_mask(dev, B43_LPPHY_AFE_DAC_CTL, 0xF7FF);
213 b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0);
214 b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0);
215 b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0);
216 b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0);
217 b43_phy_set(dev, B43_LPPHY_AFE_DAC_CTL, 0x0004);
218 b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x0078);
219 b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
220 b43_phy_write(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x0016);
221 b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_0, 0xFFF8, 0x0004);
222 b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5400);
223 b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2400);
224 b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
225 b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006);
226 b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE);
227 b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005);
68ec5329
GS
228 b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0x0180);
229 b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3C00);
96909e97
GS
230 b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005);
231 b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A);
232 b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3);
233 b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
234 b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB,
235 0xFF00, lpphy->rx_pwr_offset);
236 if ((bus->sprom.boardflags_lo & B43_BFL_FEM) &&
237 ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ||
238 (bus->sprom.boardflags_hi & B43_BFH_PAREF))) {
06e4da26
GS
239 ssb_pmu_set_ldo_voltage(&bus->chipco, LDO_PAREF, 0x28);
240 ssb_pmu_set_ldo_paref(&bus->chipco, true);
96909e97
GS
241 if (dev->phy.rev == 0) {
242 b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
243 0xFFCF, 0x0010);
244 }
245 b43_lptab_write(dev, B43_LPTAB16(11, 7), 60);
246 } else {
06e4da26 247 ssb_pmu_set_ldo_paref(&bus->chipco, false);
96909e97
GS
248 b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
249 0xFFCF, 0x0020);
250 b43_lptab_write(dev, B43_LPTAB16(11, 7), 100);
251 }
252 tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000;
253 b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp);
254 if (bus->sprom.boardflags_hi & B43_BFH_RSSIINV)
255 b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA);
256 else
257 b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA);
258 b43_lptab_write(dev, B43_LPTAB16(11, 1), 24);
259 b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL,
260 0xFFF9, (lpphy->bx_arch << 1));
738f0f43
GS
261 if (dev->phy.rev == 1 &&
262 (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) {
263 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
264 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900);
265 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
266 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
267 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x000A);
268 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0400);
269 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x000A);
270 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0B00);
271 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xFFC0, 0x000A);
272 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xC0FF, 0x0900);
273 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xFFC0, 0x000A);
274 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xC0FF, 0x0B00);
275 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xFFC0, 0x000A);
276 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xC0FF, 0x0900);
277 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A);
278 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00);
279 } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ ||
280 (bus->boardinfo.type == 0x048A) || ((dev->phy.rev == 0) &&
281 (bus->sprom.boardflags_lo & B43_BFL_FEM))) {
282 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001);
283 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400);
284 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001);
285 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0500);
286 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
287 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0800);
288 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
289 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00);
290 } else if (dev->phy.rev == 1 ||
291 (bus->sprom.boardflags_lo & B43_BFL_FEM)) {
292 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004);
293 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800);
294 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004);
295 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0C00);
296 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
297 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0100);
298 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
299 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0300);
300 } else {
301 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
302 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0900);
303 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
304 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
305 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0006);
306 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0500);
307 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006);
308 b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700);
309 }
96909e97 310 if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_PAREF)) {
738f0f43
GS
311 b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1);
312 b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2);
313 b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3);
314 b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_8, B43_LPPHY_TR_LOOKUP_4);
315 }
316 if ((bus->sprom.boardflags_hi & B43_BFH_FEM_BT) &&
317 (bus->chip_id == 0x5354) &&
318 (bus->chip_package == SSB_CHIPPACK_BCM4712S)) {
319 b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006);
320 b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005);
321 b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF);
96909e97 322 //FIXME the Broadcom driver caches & delays this HF write!
7c81e98a 323 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W);
738f0f43
GS
324 }
325 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
326 b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000);
327 b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0040);
328 b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0xA400);
329 b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0x0B00);
330 b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x0007);
331 b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFF8, 0x0003);
332 b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFC7, 0x0020);
333 b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
334 } else { /* 5GHz */
335 b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0x7FFF);
336 b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFBF);
337 }
338 if (dev->phy.rev == 1) {
339 tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH);
340 tmp2 = (tmp & 0x03E0) >> 5;
68ec5329 341 tmp2 |= tmp2 << 5;
738f0f43 342 b43_phy_write(dev, B43_LPPHY_4C3, tmp2);
68ec5329 343 tmp = b43_phy_read(dev, B43_LPPHY_GAINDIRECTMISMATCH);
738f0f43 344 tmp2 = (tmp & 0x1F00) >> 8;
68ec5329 345 tmp2 |= tmp2 << 5;
738f0f43
GS
346 b43_phy_write(dev, B43_LPPHY_4C4, tmp2);
347 tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB);
348 tmp2 = tmp & 0x00FF;
349 tmp2 |= tmp << 8;
350 b43_phy_write(dev, B43_LPPHY_4C5, tmp2);
351 }
a387cc7d
MB
352}
353
a3e14f3d
GS
354static void lpphy_save_dig_flt_state(struct b43_wldev *dev)
355{
356 static const u16 addr[] = {
357 B43_PHY_OFDM(0xC1),
358 B43_PHY_OFDM(0xC2),
359 B43_PHY_OFDM(0xC3),
360 B43_PHY_OFDM(0xC4),
361 B43_PHY_OFDM(0xC5),
362 B43_PHY_OFDM(0xC6),
363 B43_PHY_OFDM(0xC7),
364 B43_PHY_OFDM(0xC8),
365 B43_PHY_OFDM(0xCF),
366 };
367
368 static const u16 coefs[] = {
369 0xDE5E, 0xE832, 0xE331, 0x4D26,
370 0x0026, 0x1420, 0x0020, 0xFE08,
371 0x0008,
372 };
373
374 struct b43_phy_lp *lpphy = dev->phy.lp;
375 int i;
376
377 for (i = 0; i < ARRAY_SIZE(addr); i++) {
378 lpphy->dig_flt_state[i] = b43_phy_read(dev, addr[i]);
379 b43_phy_write(dev, addr[i], coefs[i]);
380 }
381}
382
383static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
384{
385 static const u16 addr[] = {
386 B43_PHY_OFDM(0xC1),
387 B43_PHY_OFDM(0xC2),
388 B43_PHY_OFDM(0xC3),
389 B43_PHY_OFDM(0xC4),
390 B43_PHY_OFDM(0xC5),
391 B43_PHY_OFDM(0xC6),
392 B43_PHY_OFDM(0xC7),
393 B43_PHY_OFDM(0xC8),
394 B43_PHY_OFDM(0xCF),
395 };
396
397 struct b43_phy_lp *lpphy = dev->phy.lp;
398 int i;
399
400 for (i = 0; i < ARRAY_SIZE(addr); i++)
401 b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]);
402}
403
a387cc7d
MB
404static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
405{
686aa5f2 406 struct ssb_bus *bus = dev->dev->bus;
6c1bb927
MB
407 struct b43_phy_lp *lpphy = dev->phy.lp;
408
409 b43_phy_write(dev, B43_LPPHY_AFE_DAC_CTL, 0x50);
410 b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0x8800);
411 b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0);
412 b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0);
413 b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0);
414 b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0);
415 b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0);
416 b43_phy_write(dev, B43_LPPHY_TR_LOOKUP_1, 0);
417 b43_phy_set(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x10);
a3e14f3d 418 b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0xB4);
6c1bb927
MB
419 b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xF8FF, 0x200);
420 b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xFF00, 0x7F);
421 b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFF0F, 0x40);
422 b43_phy_maskset(dev, B43_LPPHY_PREAMBLECONFIRMTO, 0xFF00, 0x2);
423 b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000);
424 b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000);
425 b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1);
a3e14f3d
GS
426 if (bus->boardinfo.rev >= 0x18) {
427 b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC);
428 b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14);
429 } else {
430 b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10);
431 }
6c1bb927 432 b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0xFF00, 0xF4);
24b5bcc6 433 b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0x00FF, 0xF100);
6c1bb927
MB
434 b43_phy_write(dev, B43_LPPHY_CLIPTHRESH, 0x48);
435 b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0xFF00, 0x46);
436 b43_phy_maskset(dev, B43_PHY_OFDM(0xE4), 0xFF00, 0x10);
437 b43_phy_maskset(dev, B43_LPPHY_PWR_THRESH1, 0xFFF0, 0x9);
438 b43_phy_mask(dev, B43_LPPHY_GAINDIRECTMISMATCH, ~0xF);
439 b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5500);
96909e97 440 b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0);
6c1bb927
MB
441 b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300);
442 b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00);
686aa5f2
MB
443 if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
444 b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
445 b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0xA);
446 } else {
447 b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x1E00);
448 b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0xD);
449 }
6c1bb927
MB
450 b43_phy_maskset(dev, B43_PHY_OFDM(0xFE), 0xFFE0, 0x1F);
451 b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0xFFE0, 0xC);
452 b43_phy_maskset(dev, B43_PHY_OFDM(0x100), 0xFF00, 0x19);
453 b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0x03FF, 0x3C00);
454 b43_phy_maskset(dev, B43_PHY_OFDM(0xFE), 0xFC1F, 0x3E0);
455 b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0xFFE0, 0xC);
456 b43_phy_maskset(dev, B43_PHY_OFDM(0x100), 0x00FF, 0x1900);
457 b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
458 b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12);
459 b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000);
460
96909e97 461 if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
a3e14f3d
GS
462 b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0);
463 b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40);
464 }
6c1bb927
MB
465
466 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
467 b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x40);
468 b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0xB00);
469 b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x6);
470 b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0x9D00);
471 b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0xFF00, 0xA1);
96909e97 472 b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
6c1bb927
MB
473 } else /* 5GHz */
474 b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x40);
475
476 b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0xB3);
477 b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
478 b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB, 0xFF00, lpphy->rx_pwr_offset);
479 b43_phy_set(dev, B43_LPPHY_RESET_CTL, 0x44);
480 b43_phy_write(dev, B43_LPPHY_RESET_CTL, 0x80);
481 b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, 0xA954);
482 b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_1,
483 0x2000 | ((u16)lpphy->rssi_gs << 10) |
484 ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf);
a3e14f3d
GS
485
486 if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
487 b43_phy_set(dev, B43_LPPHY_AFE_ADC_CTL_0, 0x1C);
488 b43_phy_maskset(dev, B43_LPPHY_AFE_CTL, 0x00FF, 0x8800);
489 b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_1, 0xFC3C, 0x0400);
490 }
491
492 lpphy_save_dig_flt_state(dev);
a387cc7d
MB
493}
494
495static void lpphy_baseband_init(struct b43_wldev *dev)
496{
497 lpphy_table_init(dev);
498 if (dev->phy.rev >= 2)
499 lpphy_baseband_rev2plus_init(dev);
500 else
501 lpphy_baseband_rev0_1_init(dev);
502}
503
24b5bcc6
MB
504struct b2062_freqdata {
505 u16 freq;
506 u8 data[6];
507};
508
509/* Initialize the 2062 radio. */
510static void lpphy_2062_init(struct b43_wldev *dev)
511{
1e711bee 512 struct b43_phy_lp *lpphy = dev->phy.lp;
99e0fca6 513 struct ssb_bus *bus = dev->dev->bus;
1e711bee 514 u32 crystalfreq, tmp, ref;
24b5bcc6
MB
515 unsigned int i;
516 const struct b2062_freqdata *fd = NULL;
517
518 static const struct b2062_freqdata freqdata_tab[] = {
519 { .freq = 12000, .data[0] = 6, .data[1] = 6, .data[2] = 6,
520 .data[3] = 6, .data[4] = 10, .data[5] = 6, },
521 { .freq = 13000, .data[0] = 4, .data[1] = 4, .data[2] = 4,
522 .data[3] = 4, .data[4] = 11, .data[5] = 7, },
523 { .freq = 14400, .data[0] = 3, .data[1] = 3, .data[2] = 3,
524 .data[3] = 3, .data[4] = 12, .data[5] = 7, },
525 { .freq = 16200, .data[0] = 3, .data[1] = 3, .data[2] = 3,
526 .data[3] = 3, .data[4] = 13, .data[5] = 8, },
527 { .freq = 18000, .data[0] = 2, .data[1] = 2, .data[2] = 2,
528 .data[3] = 2, .data[4] = 14, .data[5] = 8, },
529 { .freq = 19200, .data[0] = 1, .data[1] = 1, .data[2] = 1,
530 .data[3] = 1, .data[4] = 14, .data[5] = 9, },
531 };
532
533 b2062_upload_init_table(dev);
534
535 b43_radio_write(dev, B2062_N_TX_CTL3, 0);
536 b43_radio_write(dev, B2062_N_TX_CTL4, 0);
537 b43_radio_write(dev, B2062_N_TX_CTL5, 0);
7e4d8529 538 b43_radio_write(dev, B2062_N_TX_CTL6, 0);
24b5bcc6
MB
539 b43_radio_write(dev, B2062_N_PDN_CTL0, 0x40);
540 b43_radio_write(dev, B2062_N_PDN_CTL0, 0);
541 b43_radio_write(dev, B2062_N_CALIB_TS, 0x10);
542 b43_radio_write(dev, B2062_N_CALIB_TS, 0);
7e4d8529
GS
543 if (dev->phy.rev > 0) {
544 b43_radio_write(dev, B2062_S_BG_CTL1,
545 (b43_radio_read(dev, B2062_N_COMM2) >> 1) | 0x80);
546 }
24b5bcc6
MB
547 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
548 b43_radio_set(dev, B2062_N_TSSI_CTL0, 0x1);
549 else
550 b43_radio_mask(dev, B2062_N_TSSI_CTL0, ~0x1);
551
99e0fca6
MB
552 /* Get the crystal freq, in Hz. */
553 crystalfreq = bus->chipco.pmu.crystalfreq * 1000;
554
555 B43_WARN_ON(!(bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU));
556 B43_WARN_ON(crystalfreq == 0);
24b5bcc6 557
5269102e 558 if (crystalfreq <= 30000000) {
1e711bee 559 lpphy->pdiv = 1;
24b5bcc6
MB
560 b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB);
561 } else {
1e711bee 562 lpphy->pdiv = 2;
24b5bcc6
MB
563 b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4);
564 }
565
5269102e
GS
566 tmp = (((800000000 * lpphy->pdiv + crystalfreq) /
567 (2 * crystalfreq)) - 8) & 0xFF;
568 b43_radio_write(dev, B2062_S_RFPLL_CTL7, tmp);
569
570 tmp = (((100 * crystalfreq + 16000000 * lpphy->pdiv) /
571 (32000000 * lpphy->pdiv)) - 1) & 0xFF;
24b5bcc6
MB
572 b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp);
573
5269102e
GS
574 tmp = (((2 * crystalfreq + 1000000 * lpphy->pdiv) /
575 (2000000 * lpphy->pdiv)) - 1) & 0xFF;
24b5bcc6
MB
576 b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp);
577
1e711bee 578 ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv);
24b5bcc6
MB
579 ref &= 0xFFFF;
580 for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) {
581 if (ref < freqdata_tab[i].freq) {
582 fd = &freqdata_tab[i];
583 break;
584 }
585 }
99e0fca6
MB
586 if (!fd)
587 fd = &freqdata_tab[ARRAY_SIZE(freqdata_tab) - 1];
588 b43dbg(dev->wl, "b2062: Using crystal tab entry %u kHz.\n",
589 fd->freq); /* FIXME: Keep this printk until the code is fully debugged. */
24b5bcc6
MB
590
591 b43_radio_write(dev, B2062_S_RFPLL_CTL8,
592 ((u16)(fd->data[1]) << 4) | fd->data[0]);
593 b43_radio_write(dev, B2062_S_RFPLL_CTL9,
99e0fca6 594 ((u16)(fd->data[3]) << 4) | fd->data[2]);
24b5bcc6
MB
595 b43_radio_write(dev, B2062_S_RFPLL_CTL10, fd->data[4]);
596 b43_radio_write(dev, B2062_S_RFPLL_CTL11, fd->data[5]);
597}
598
599/* Initialize the 2063 radio. */
600static void lpphy_2063_init(struct b43_wldev *dev)
a387cc7d 601{
c10e47f4
GS
602 b2063_upload_init_table(dev);
603 b43_radio_write(dev, B2063_LOGEN_SP5, 0);
604 b43_radio_set(dev, B2063_COMM8, 0x38);
605 b43_radio_write(dev, B2063_REG_SP1, 0x56);
606 b43_radio_mask(dev, B2063_RX_BB_CTL2, ~0x2);
607 b43_radio_write(dev, B2063_PA_SP7, 0);
608 b43_radio_write(dev, B2063_TX_RF_SP6, 0x20);
609 b43_radio_write(dev, B2063_TX_RF_SP9, 0x40);
5791ce18
GS
610 if (dev->phy.rev == 2) {
611 b43_radio_write(dev, B2063_PA_SP3, 0xa0);
612 b43_radio_write(dev, B2063_PA_SP4, 0xa0);
613 b43_radio_write(dev, B2063_PA_SP2, 0x18);
614 } else {
615 b43_radio_write(dev, B2063_PA_SP3, 0x20);
616 b43_radio_write(dev, B2063_PA_SP2, 0x20);
617 }
a387cc7d
MB
618}
619
3281d95d
GS
620struct lpphy_stx_table_entry {
621 u16 phy_offset;
622 u16 phy_shift;
623 u16 rf_addr;
624 u16 rf_shift;
625 u16 mask;
626};
627
628static const struct lpphy_stx_table_entry lpphy_stx_table[] = {
629 { .phy_offset = 2, .phy_shift = 6, .rf_addr = 0x3d, .rf_shift = 3, .mask = 0x01, },
630 { .phy_offset = 1, .phy_shift = 12, .rf_addr = 0x4c, .rf_shift = 1, .mask = 0x01, },
631 { .phy_offset = 1, .phy_shift = 8, .rf_addr = 0x50, .rf_shift = 0, .mask = 0x7f, },
632 { .phy_offset = 0, .phy_shift = 8, .rf_addr = 0x44, .rf_shift = 0, .mask = 0xff, },
633 { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4a, .rf_shift = 0, .mask = 0xff, },
634 { .phy_offset = 0, .phy_shift = 4, .rf_addr = 0x4d, .rf_shift = 0, .mask = 0xff, },
635 { .phy_offset = 1, .phy_shift = 4, .rf_addr = 0x4e, .rf_shift = 0, .mask = 0xff, },
636 { .phy_offset = 0, .phy_shift = 12, .rf_addr = 0x4f, .rf_shift = 0, .mask = 0x0f, },
637 { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4f, .rf_shift = 4, .mask = 0x0f, },
638 { .phy_offset = 3, .phy_shift = 0, .rf_addr = 0x49, .rf_shift = 0, .mask = 0x0f, },
639 { .phy_offset = 4, .phy_shift = 3, .rf_addr = 0x46, .rf_shift = 4, .mask = 0x07, },
640 { .phy_offset = 3, .phy_shift = 15, .rf_addr = 0x46, .rf_shift = 0, .mask = 0x01, },
641 { .phy_offset = 4, .phy_shift = 0, .rf_addr = 0x46, .rf_shift = 1, .mask = 0x07, },
642 { .phy_offset = 3, .phy_shift = 8, .rf_addr = 0x48, .rf_shift = 4, .mask = 0x07, },
643 { .phy_offset = 3, .phy_shift = 11, .rf_addr = 0x48, .rf_shift = 0, .mask = 0x0f, },
644 { .phy_offset = 3, .phy_shift = 4, .rf_addr = 0x49, .rf_shift = 4, .mask = 0x0f, },
645 { .phy_offset = 2, .phy_shift = 15, .rf_addr = 0x45, .rf_shift = 0, .mask = 0x01, },
646 { .phy_offset = 5, .phy_shift = 13, .rf_addr = 0x52, .rf_shift = 4, .mask = 0x07, },
647 { .phy_offset = 6, .phy_shift = 0, .rf_addr = 0x52, .rf_shift = 7, .mask = 0x01, },
648 { .phy_offset = 5, .phy_shift = 3, .rf_addr = 0x41, .rf_shift = 5, .mask = 0x07, },
649 { .phy_offset = 5, .phy_shift = 6, .rf_addr = 0x41, .rf_shift = 0, .mask = 0x0f, },
650 { .phy_offset = 5, .phy_shift = 10, .rf_addr = 0x42, .rf_shift = 5, .mask = 0x07, },
651 { .phy_offset = 4, .phy_shift = 15, .rf_addr = 0x42, .rf_shift = 0, .mask = 0x01, },
652 { .phy_offset = 5, .phy_shift = 0, .rf_addr = 0x42, .rf_shift = 1, .mask = 0x07, },
653 { .phy_offset = 4, .phy_shift = 11, .rf_addr = 0x43, .rf_shift = 4, .mask = 0x0f, },
654 { .phy_offset = 4, .phy_shift = 7, .rf_addr = 0x43, .rf_shift = 0, .mask = 0x0f, },
655 { .phy_offset = 4, .phy_shift = 6, .rf_addr = 0x45, .rf_shift = 1, .mask = 0x01, },
656 { .phy_offset = 2, .phy_shift = 7, .rf_addr = 0x40, .rf_shift = 4, .mask = 0x0f, },
657 { .phy_offset = 2, .phy_shift = 11, .rf_addr = 0x40, .rf_shift = 0, .mask = 0x0f, },
658};
659
24b5bcc6
MB
660static void lpphy_sync_stx(struct b43_wldev *dev)
661{
3281d95d
GS
662 const struct lpphy_stx_table_entry *e;
663 unsigned int i;
664 u16 tmp;
665
666 for (i = 0; i < ARRAY_SIZE(lpphy_stx_table); i++) {
667 e = &lpphy_stx_table[i];
668 tmp = b43_radio_read(dev, e->rf_addr);
669 tmp >>= e->rf_shift;
670 tmp <<= e->phy_shift;
671 b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset),
d44517f2 672 ~(e->mask << e->phy_shift), tmp);
3281d95d 673 }
24b5bcc6
MB
674}
675
676static void lpphy_radio_init(struct b43_wldev *dev)
677{
678 /* The radio is attached through the 4wire bus. */
679 b43_phy_set(dev, B43_LPPHY_FOURWIRE_CTL, 0x2);
680 udelay(1);
681 b43_phy_mask(dev, B43_LPPHY_FOURWIRE_CTL, 0xFFFD);
682 udelay(1);
683
5269102e 684 if (dev->phy.radio_ver == 0x2062) {
24b5bcc6
MB
685 lpphy_2062_init(dev);
686 } else {
687 lpphy_2063_init(dev);
688 lpphy_sync_stx(dev);
689 b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80);
690 b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0);
3281d95d
GS
691 if (dev->dev->bus->chip_id == 0x4325) {
692 // TODO SSB PMU recalibration
693 }
24b5bcc6
MB
694 }
695}
696
560ad81b
GS
697struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; };
698
d4de9532
GS
699static void lpphy_set_rc_cap(struct b43_wldev *dev)
700{
5269102e
GS
701 struct b43_phy_lp *lpphy = dev->phy.lp;
702
703 u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1;
d4de9532 704
5269102e 705 if (dev->phy.rev == 1) //FIXME check channel 14!
6bd5f520 706 rc_cap = min_t(u8, rc_cap + 5, 15);
5269102e
GS
707
708 b43_radio_write(dev, B2062_N_RXBB_CALIB2,
709 max_t(u8, lpphy->rc_cap - 4, 0x80));
710 b43_radio_write(dev, B2062_N_TX_CTL_A, rc_cap | 0x80);
711 b43_radio_write(dev, B2062_S_RXG_CNT16,
712 ((lpphy->rc_cap & 0x1F) >> 2) | 0x80);
d4de9532
GS
713}
714
560ad81b 715static u8 lpphy_get_bb_mult(struct b43_wldev *dev)
d4de9532 716{
560ad81b 717 return (b43_lptab_read(dev, B43_LPTAB16(0, 87)) & 0xFF00) >> 8;
d4de9532
GS
718}
719
560ad81b 720static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult)
d4de9532 721{
560ad81b
GS
722 b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8);
723}
d4de9532 724
5904d206 725static void lpphy_set_deaf(struct b43_wldev *dev, bool user)
560ad81b 726{
5904d206
GS
727 struct b43_phy_lp *lpphy = dev->phy.lp;
728
729 if (user)
730 lpphy->crs_usr_disable = 1;
731 else
732 lpphy->crs_sys_disable = 1;
560ad81b 733 b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80);
5904d206
GS
734}
735
736static void lpphy_clear_deaf(struct b43_wldev *dev, bool user)
737{
738 struct b43_phy_lp *lpphy = dev->phy.lp;
739
740 if (user)
741 lpphy->crs_usr_disable = 0;
742 else
743 lpphy->crs_sys_disable = 0;
744
745 if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) {
746 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
747 b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
748 0xFF1F, 0x60);
749 else
750 b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
751 0xFF1F, 0x20);
752 }
753}
754
2c0d6100
GS
755static void lpphy_set_trsw_over(struct b43_wldev *dev, bool tx, bool rx)
756{
757 u16 trsw = (tx << 1) | rx;
758 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, trsw);
759 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
760}
761
5904d206
GS
762static void lpphy_disable_crs(struct b43_wldev *dev, bool user)
763{
764 lpphy_set_deaf(dev, user);
2c0d6100 765 lpphy_set_trsw_over(dev, false, true);
560ad81b
GS
766 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
767 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4);
68ec5329 768 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7);
560ad81b
GS
769 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
770 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10);
771 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
772 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFDF);
773 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
774 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFBF);
775 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
776 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x7);
777 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x38);
778 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F);
779 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x100);
780 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF);
781 b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL0, 0);
782 b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL1, 1);
783 b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL2, 0x20);
784 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF);
785 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF);
786 b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
787 b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45AF);
788 b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF);
789}
d4de9532 790
5904d206 791static void lpphy_restore_crs(struct b43_wldev *dev, bool user)
560ad81b 792{
5904d206 793 lpphy_clear_deaf(dev, user);
560ad81b
GS
794 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80);
795 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00);
796}
797
798struct lpphy_tx_gains { u16 gm, pga, pad, dac; };
799
2c0d6100
GS
800static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
801{
802 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
803 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
804 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
805 if (dev->phy.rev >= 2) {
806 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
807 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
808 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
809 b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
810 }
811 } else {
812 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
813 }
814}
815
816static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
817{
818 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
819 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
820 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
821 if (dev->phy.rev >= 2) {
822 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
823 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
824 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
825 b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
826 }
827 } else {
828 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
829 }
830}
831
832static void lpphy_disable_tx_gain_override(struct b43_wldev *dev)
833{
834 if (dev->phy.rev < 2)
835 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
836 else {
837 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F);
838 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF);
839 }
840 b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF);
841}
842
843static void lpphy_enable_tx_gain_override(struct b43_wldev *dev)
844{
845 if (dev->phy.rev < 2)
846 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
847 else {
848 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x80);
849 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x4000);
850 }
851 b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x40);
852}
853
560ad81b
GS
854static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev)
855{
856 struct lpphy_tx_gains gains;
857 u16 tmp;
858
859 gains.dac = (b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0x380) >> 7;
860 if (dev->phy.rev < 2) {
861 tmp = b43_phy_read(dev,
862 B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7FF;
863 gains.gm = tmp & 0x0007;
864 gains.pga = (tmp & 0x0078) >> 3;
865 gains.pad = (tmp & 0x780) >> 7;
866 } else {
867 tmp = b43_phy_read(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL);
868 gains.pad = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0xFF;
869 gains.gm = tmp & 0xFF;
870 gains.pga = (tmp >> 8) & 0xFF;
d4de9532
GS
871 }
872
560ad81b
GS
873 return gains;
874}
d4de9532 875
560ad81b
GS
876static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac)
877{
878 u16 ctl = b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0xC7F;
879 ctl |= dac << 7;
880 b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl);
881}
d4de9532 882
2c0d6100
GS
883static u16 lpphy_get_pa_gain(struct b43_wldev *dev)
884{
885 return b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F;
886}
887
888static void lpphy_set_pa_gain(struct b43_wldev *dev, u16 gain)
889{
890 b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), 0xE03F, gain << 6);
891 b43_phy_maskset(dev, B43_PHY_OFDM(0xFD), 0x80FF, gain << 8);
892}
893
560ad81b
GS
894static void lpphy_set_tx_gains(struct b43_wldev *dev,
895 struct lpphy_tx_gains gains)
896{
897 u16 rf_gain, pa_gain;
d4de9532 898
560ad81b
GS
899 if (dev->phy.rev < 2) {
900 rf_gain = (gains.pad << 7) | (gains.pga << 3) | gains.gm;
901 b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
902 0xF800, rf_gain);
d4de9532 903 } else {
2c0d6100 904 pa_gain = lpphy_get_pa_gain(dev);
560ad81b
GS
905 b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
906 (gains.pga << 8) | gains.gm);
2c0d6100
GS
907 /*
908 * SPEC FIXME The spec calls for (pa_gain << 8) here, but that
909 * conflicts with the spec for set_pa_gain! Vendor driver bug?
910 */
5904d206 911 b43_phy_maskset(dev, B43_PHY_OFDM(0xFB),
2c0d6100 912 0x8000, gains.pad | (pa_gain << 6));
560ad81b
GS
913 b43_phy_write(dev, B43_PHY_OFDM(0xFC),
914 (gains.pga << 8) | gains.gm);
915 b43_phy_maskset(dev, B43_PHY_OFDM(0xFD),
2c0d6100 916 0x8000, gains.pad | (pa_gain << 8));
d4de9532 917 }
560ad81b 918 lpphy_set_dac_gain(dev, gains.dac);
2c0d6100 919 lpphy_enable_tx_gain_override(dev);
560ad81b 920}
d4de9532 921
560ad81b
GS
922static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
923{
924 u16 trsw = gain & 0x1;
925 u16 lna = (gain & 0xFFFC) | ((gain & 0xC) >> 2);
926 u16 ext_lna = (gain & 2) >> 1;
927
928 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
929 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
930 0xFBFF, ext_lna << 10);
931 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
932 0xF7FF, ext_lna << 11);
933 b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
934}
d4de9532 935
560ad81b
GS
936static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
937{
938 u16 low_gain = gain & 0xFFFF;
939 u16 high_gain = (gain >> 16) & 0xF;
940 u16 ext_lna = (gain >> 21) & 0x1;
941 u16 trsw = ~(gain >> 20) & 0x1;
942 u16 tmp;
943
944 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
945 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
946 0xFDFF, ext_lna << 9);
947 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
948 0xFBFF, ext_lna << 10);
949 b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
950 b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF0, high_gain);
951 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
952 tmp = (gain >> 2) & 0x3;
953 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
954 0xE7FF, tmp<<11);
955 b43_phy_maskset(dev, B43_PHY_OFDM(0xE6), 0xFFE7, tmp << 3);
956 }
957}
958
560ad81b
GS
959static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain)
960{
961 if (dev->phy.rev < 2)
962 lpphy_rev0_1_set_rx_gain(dev, gain);
963 else
964 lpphy_rev2plus_set_rx_gain(dev, gain);
965 lpphy_enable_rx_gain_override(dev);
966}
967
968static void lpphy_set_rx_gain_by_index(struct b43_wldev *dev, u16 idx)
969{
970 u32 gain = b43_lptab_read(dev, B43_LPTAB16(12, idx));
971 lpphy_set_rx_gain(dev, gain);
972}
973
974static void lpphy_stop_ddfs(struct b43_wldev *dev)
975{
976 b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFD);
977 b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xFFDF);
978}
979
980static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on,
981 int incr1, int incr2, int scale_idx)
982{
983 lpphy_stop_ddfs(dev);
984 b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0xFF80);
985 b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0x80FF);
986 b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0xFF80, incr1);
987 b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0x80FF, incr2 << 8);
988 b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF7, i_on << 3);
989 b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFEF, q_on << 4);
990 b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5);
991 b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB);
992 b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2);
68ec5329 993 b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x20);
560ad81b
GS
994}
995
996static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time,
997 struct lpphy_iq_est *iq_est)
998{
999 int i;
1000
1001 b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFF7);
1002 b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples);
1003 b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time);
1004 b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF);
68ec5329 1005 b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
560ad81b
GS
1006
1007 for (i = 0; i < 500; i++) {
1008 if (!(b43_phy_read(dev,
1009 B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
d4de9532
GS
1010 break;
1011 msleep(1);
1012 }
1013
560ad81b
GS
1014 if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
1015 b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
1016 return false;
1017 }
d4de9532 1018
560ad81b
GS
1019 iq_est->iq_prod = b43_phy_read(dev, B43_LPPHY_IQ_ACC_HI_ADDR);
1020 iq_est->iq_prod <<= 16;
1021 iq_est->iq_prod |= b43_phy_read(dev, B43_LPPHY_IQ_ACC_LO_ADDR);
1022
1023 iq_est->i_pwr = b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_HI_ADDR);
1024 iq_est->i_pwr <<= 16;
1025 iq_est->i_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_LO_ADDR);
1026
1027 iq_est->q_pwr = b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_HI_ADDR);
1028 iq_est->q_pwr <<= 16;
1029 iq_est->q_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_LO_ADDR);
1030
1031 b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
1032 return true;
d4de9532
GS
1033}
1034
560ad81b 1035static int lpphy_loopback(struct b43_wldev *dev)
d4de9532 1036{
560ad81b
GS
1037 struct lpphy_iq_est iq_est;
1038 int i, index = -1;
1039 u32 tmp;
1040
1041 memset(&iq_est, 0, sizeof(iq_est));
1042
2c0d6100 1043 lpphy_set_trsw_over(dev, true, true);
6bd5f520 1044 b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1);
560ad81b
GS
1045 b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
1046 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
1047 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
1048 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
1049 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x8);
1050 b43_radio_write(dev, B2062_N_TX_CTL_A, 0x80);
1051 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x80);
1052 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x80);
1053 for (i = 0; i < 32; i++) {
1054 lpphy_set_rx_gain_by_index(dev, i);
1055 lpphy_run_ddfs(dev, 1, 1, 5, 5, 0);
1056 if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
1057 continue;
1058 tmp = (iq_est.i_pwr + iq_est.q_pwr) / 1000;
1059 if ((tmp > 4000) && (tmp < 10000)) {
1060 index = i;
1061 break;
1062 }
1063 }
1064 lpphy_stop_ddfs(dev);
1065 return index;
1066}
d4de9532 1067
d8fa338e 1068/* Fixed-point division algorithm using only integer math. */
560ad81b
GS
1069static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
1070{
d8fa338e 1071 u32 quotient, remainder;
560ad81b 1072
5904d206
GS
1073 if (divisor == 0)
1074 return 0;
1075
1076 quotient = dividend / divisor;
1077 remainder = dividend % divisor;
560ad81b 1078
d8fa338e 1079 while (precision > 0) {
560ad81b 1080 quotient <<= 1;
d8fa338e
GS
1081 if (remainder << 1 >= divisor) {
1082 quotient++;
1083 remainder = (remainder << 1) - divisor;
1084 }
560ad81b
GS
1085 precision--;
1086 }
1087
d8fa338e 1088 if (remainder << 1 >= divisor)
560ad81b
GS
1089 quotient++;
1090
1091 return quotient;
d4de9532
GS
1092}
1093
ce1a9ee3
MB
1094/* Read the TX power control mode from hardware. */
1095static void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev)
1096{
1097 struct b43_phy_lp *lpphy = dev->phy.lp;
1098 u16 ctl;
1099
1100 ctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD);
1101 switch (ctl & B43_LPPHY_TX_PWR_CTL_CMD_MODE) {
1102 case B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF:
1103 lpphy->txpctl_mode = B43_LPPHY_TXPCTL_OFF;
1104 break;
1105 case B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW:
1106 lpphy->txpctl_mode = B43_LPPHY_TXPCTL_SW;
1107 break;
1108 case B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW:
1109 lpphy->txpctl_mode = B43_LPPHY_TXPCTL_HW;
1110 break;
1111 default:
1112 lpphy->txpctl_mode = B43_LPPHY_TXPCTL_UNKNOWN;
1113 B43_WARN_ON(1);
1114 break;
1115 }
1116}
1117
1118/* Set the TX power control mode in hardware. */
1119static void lpphy_write_tx_pctl_mode_to_hardware(struct b43_wldev *dev)
1120{
1121 struct b43_phy_lp *lpphy = dev->phy.lp;
1122 u16 ctl;
1123
1124 switch (lpphy->txpctl_mode) {
1125 case B43_LPPHY_TXPCTL_OFF:
1126 ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF;
1127 break;
1128 case B43_LPPHY_TXPCTL_HW:
1129 ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW;
1130 break;
1131 case B43_LPPHY_TXPCTL_SW:
1132 ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW;
1133 break;
1134 default:
1135 ctl = 0;
1136 B43_WARN_ON(1);
1137 }
1138 b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
1139 (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, ctl);
1140}
1141
1142static void lpphy_set_tx_power_control(struct b43_wldev *dev,
1143 enum b43_lpphy_txpctl_mode mode)
1144{
1145 struct b43_phy_lp *lpphy = dev->phy.lp;
1146 enum b43_lpphy_txpctl_mode oldmode;
1147
ce1a9ee3 1148 lpphy_read_tx_pctl_mode_from_hardware(dev);
12d4bba0
GS
1149 oldmode = lpphy->txpctl_mode;
1150 if (oldmode == mode)
ce1a9ee3
MB
1151 return;
1152 lpphy->txpctl_mode = mode;
1153
1154 if (oldmode == B43_LPPHY_TXPCTL_HW) {
1155 //TODO Update TX Power NPT
1156 //TODO Clear all TX Power offsets
1157 } else {
1158 if (mode == B43_LPPHY_TXPCTL_HW) {
1159 //TODO Recalculate target TX power
1160 b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
1161 0xFF80, lpphy->tssi_idx);
1162 b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM,
1163 0x8FFF, ((u16)lpphy->tssi_npt << 16));
1164 //TODO Set "TSSI Transmit Count" variable to total transmitted frame count
2c0d6100 1165 lpphy_disable_tx_gain_override(dev);
ce1a9ee3
MB
1166 lpphy->tx_pwr_idx_over = -1;
1167 }
1168 }
1169 if (dev->phy.rev >= 2) {
1170 if (mode == B43_LPPHY_TXPCTL_HW)
68ec5329 1171 b43_phy_set(dev, B43_PHY_OFDM(0xD0), 0x2);
ce1a9ee3 1172 else
68ec5329 1173 b43_phy_mask(dev, B43_PHY_OFDM(0xD0), 0xFFFD);
ce1a9ee3
MB
1174 }
1175 lpphy_write_tx_pctl_mode_to_hardware(dev);
1176}
1177
5269102e
GS
1178static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
1179 unsigned int new_channel);
1180
560ad81b
GS
1181static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
1182{
1183 struct b43_phy_lp *lpphy = dev->phy.lp;
1184 struct lpphy_iq_est iq_est;
1185 struct lpphy_tx_gains tx_gains;
5904d206 1186 static const u32 ideal_pwr_table[21] = {
560ad81b
GS
1187 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
1188 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
1189 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
5904d206 1190 0x0004c, 0x0002c, 0x0001a,
560ad81b
GS
1191 };
1192 bool old_txg_ovr;
1193 u8 old_bbmult;
1194 u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval,
1245684c
GS
1195 old_rf2_ovr, old_rf2_ovrval, old_phy_ctl;
1196 enum b43_lpphy_txpctl_mode old_txpctl;
560ad81b 1197 u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0;
5269102e 1198 int loopback, i, j, inner_sum, err;
560ad81b
GS
1199
1200 memset(&iq_est, 0, sizeof(iq_est));
1201
5269102e
GS
1202 err = b43_lpphy_op_switch_channel(dev, 7);
1203 if (err) {
1204 b43dbg(dev->wl,
68ec5329 1205 "RC calib: Failed to switch to channel 7, error = %d\n",
5269102e
GS
1206 err);
1207 }
5904d206 1208 old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40);
560ad81b
GS
1209 old_bbmult = lpphy_get_bb_mult(dev);
1210 if (old_txg_ovr)
1211 tx_gains = lpphy_get_tx_gains(dev);
1212 old_rf_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_0);
1213 old_rf_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_VAL_0);
1214 old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR);
1215 old_afe_ovrval = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVRVAL);
1216 old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2);
1217 old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL);
1218 old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL);
1245684c
GS
1219 lpphy_read_tx_pctl_mode_from_hardware(dev);
1220 old_txpctl = lpphy->txpctl_mode;
560ad81b 1221
5f1c07d9 1222 lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
5904d206 1223 lpphy_disable_crs(dev, true);
560ad81b
GS
1224 loopback = lpphy_loopback(dev);
1225 if (loopback == -1)
1226 goto finish;
1227 lpphy_set_rx_gain_by_index(dev, loopback);
1228 b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFFBF, 0x40);
1229 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFF8, 0x1);
1230 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFC7, 0x8);
1231 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F, 0xC0);
1232 for (i = 128; i <= 159; i++) {
1233 b43_radio_write(dev, B2062_N_RXBB_CALIB2, i);
1234 inner_sum = 0;
1235 for (j = 5; j <= 25; j++) {
1236 lpphy_run_ddfs(dev, 1, 1, j, j, 0);
1237 if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
1238 goto finish;
1239 mean_sq_pwr = iq_est.i_pwr + iq_est.q_pwr;
1240 if (j == 5)
1241 tmp = mean_sq_pwr;
1242 ideal_pwr = ((ideal_pwr_table[j-5] >> 3) + 1) >> 1;
1243 normal_pwr = lpphy_qdiv_roundup(mean_sq_pwr, tmp, 12);
1244 mean_sq_pwr = ideal_pwr - normal_pwr;
1245 mean_sq_pwr *= mean_sq_pwr;
1246 inner_sum += mean_sq_pwr;
6bd5f520 1247 if ((i == 128) || (inner_sum < mean_sq_pwr_min)) {
560ad81b
GS
1248 lpphy->rc_cap = i;
1249 mean_sq_pwr_min = inner_sum;
1250 }
1251 }
1252 }
1253 lpphy_stop_ddfs(dev);
1254
1255finish:
5904d206 1256 lpphy_restore_crs(dev, true);
560ad81b
GS
1257 b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval);
1258 b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr);
1259 b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval);
1260 b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, old_afe_ovr);
1261 b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, old_rf2_ovrval);
1262 b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, old_rf2_ovr);
1263 b43_phy_write(dev, B43_LPPHY_LP_PHY_CTL, old_phy_ctl);
1264
1265 lpphy_set_bb_mult(dev, old_bbmult);
1266 if (old_txg_ovr) {
1267 /*
1268 * SPEC FIXME: The specs say "get_tx_gains" here, which is
1269 * illogical. According to lwfinger, vendor driver v4.150.10.5
1270 * has a Set here, while v4.174.64.19 has a Get - regression in
1271 * the vendor driver? This should be tested this once the code
1272 * is testable.
1273 */
1274 lpphy_set_tx_gains(dev, tx_gains);
1275 }
1276 lpphy_set_tx_power_control(dev, old_txpctl);
1277 if (lpphy->rc_cap)
1278 lpphy_set_rc_cap(dev);
1279}
1280
1281static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
1282{
1283 struct ssb_bus *bus = dev->dev->bus;
1284 u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
1285 u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF;
1286 int i;
1287
1288 b43_radio_write(dev, B2063_RX_BB_SP8, 0x0);
1289 b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
1290 b43_radio_mask(dev, B2063_PLL_SP1, 0xF7);
1291 b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
1292 b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15);
1293 b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70);
1294 b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52);
1295 b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
1296 b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D);
1297
1298 for (i = 0; i < 10000; i++) {
1299 if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
1300 break;
1301 msleep(1);
1302 }
1303
1304 if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
1305 b43_radio_write(dev, B2063_RX_BB_SP8, tmp);
1306
1307 tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF;
1308
1309 b43_radio_write(dev, B2063_TX_BB_SP3, 0x0);
1310 b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
1311 b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
1312 b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55);
1313 b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76);
1314
1315 if (crystal_freq == 24000000) {
1316 b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC);
1317 b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0);
1318 } else {
1319 b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13);
1320 b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
1321 }
1322
1323 b43_radio_write(dev, B2063_PA_SP7, 0x7D);
1324
1325 for (i = 0; i < 10000; i++) {
1326 if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
1327 break;
1328 msleep(1);
1329 }
1330
1331 if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
1332 b43_radio_write(dev, B2063_TX_BB_SP3, tmp);
1333
1334 b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
1335}
1336
1337static void lpphy_calibrate_rc(struct b43_wldev *dev)
1338{
1339 struct b43_phy_lp *lpphy = dev->phy.lp;
1340
1341 if (dev->phy.rev >= 2) {
1342 lpphy_rev2plus_rc_calib(dev);
1343 } else if (!lpphy->rc_cap) {
1344 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
1345 lpphy_rev0_1_rc_calib(dev);
1346 } else {
1347 lpphy_set_rc_cap(dev);
1348 }
1349}
1350
2c0d6100
GS
1351static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
1352{
1353 if (dev->phy.rev >= 2)
1354 return; // rev2+ doesn't support antenna diversity
1355
1356 if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
1357 return;
1358
1359 b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
1360
1361 b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
1362 b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
1363
1364 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
1365
1366 dev->phy.lp->antenna = antenna;
1367}
1368
1369static void lpphy_set_tx_iqcc(struct b43_wldev *dev, u16 a, u16 b)
1370{
1371 u16 tmp[2];
1372
1373 tmp[0] = a;
1374 tmp[1] = b;
1375 b43_lptab_write_bulk(dev, B43_LPTAB16(0, 80), 2, tmp);
1376}
1377
ce1a9ee3
MB
1378static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)
1379{
1380 struct b43_phy_lp *lpphy = dev->phy.lp;
2c0d6100
GS
1381 struct lpphy_tx_gains gains;
1382 u32 iq_comp, tx_gain, coeff, rf_power;
ce1a9ee3
MB
1383
1384 lpphy->tx_pwr_idx_over = index;
2c0d6100 1385 lpphy_read_tx_pctl_mode_from_hardware(dev);
ce1a9ee3
MB
1386 if (lpphy->txpctl_mode != B43_LPPHY_TXPCTL_OFF)
1387 lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_SW);
2c0d6100
GS
1388 if (dev->phy.rev >= 2) {
1389 iq_comp = b43_lptab_read(dev, B43_LPTAB32(7, index + 320));
1390 tx_gain = b43_lptab_read(dev, B43_LPTAB32(7, index + 192));
1391 gains.pad = (tx_gain >> 16) & 0xFF;
1392 gains.gm = tx_gain & 0xFF;
1393 gains.pga = (tx_gain >> 8) & 0xFF;
1394 gains.dac = (iq_comp >> 28) & 0xFF;
1395 lpphy_set_tx_gains(dev, gains);
1396 } else {
1397 iq_comp = b43_lptab_read(dev, B43_LPTAB32(10, index + 320));
1398 tx_gain = b43_lptab_read(dev, B43_LPTAB32(10, index + 192));
1399 b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
1400 0xF800, (tx_gain >> 4) & 0x7FFF);
1401 lpphy_set_dac_gain(dev, tx_gain & 0x7);
1402 lpphy_set_pa_gain(dev, (tx_gain >> 24) & 0x7F);
1403 }
1404 lpphy_set_bb_mult(dev, (iq_comp >> 20) & 0xFF);
1405 lpphy_set_tx_iqcc(dev, (iq_comp >> 10) & 0x3FF, iq_comp & 0x3FF);
1406 if (dev->phy.rev >= 2) {
1407 coeff = b43_lptab_read(dev, B43_LPTAB32(7, index + 448));
1408 } else {
1409 coeff = b43_lptab_read(dev, B43_LPTAB32(10, index + 448));
1410 }
1411 b43_lptab_write(dev, B43_LPTAB16(0, 85), coeff & 0xFFFF);
1412 if (dev->phy.rev >= 2) {
1413 rf_power = b43_lptab_read(dev, B43_LPTAB32(7, index + 576));
1414 b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00,
1415 rf_power & 0xFFFF);//SPEC FIXME mask & set != 0
1416 }
1417 lpphy_enable_tx_gain_override(dev);
ce1a9ee3
MB
1418}
1419
1420static void lpphy_btcoex_override(struct b43_wldev *dev)
1421{
1422 b43_write16(dev, B43_MMIO_BTCOEX_CTL, 0x3);
1423 b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF);
1424}
1425
2c0d6100
GS
1426static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
1427 bool blocked)
ce1a9ee3 1428{
2c0d6100
GS
1429 //TODO check MAC control register
1430 if (blocked) {
1431 if (dev->phy.rev >= 2) {
1432 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x83FF);
1433 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
1434 b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0x80FF);
1435 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xDFFF);
1436 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0808);
1437 } else {
1438 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xE0FF);
1439 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
1440 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFCFF);
1441 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0018);
1442 }
ce1a9ee3 1443 } else {
2c0d6100
GS
1444 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xE0FF);
1445 if (dev->phy.rev >= 2)
1446 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xF7F7);
1447 else
1448 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFE7);
ce1a9ee3 1449 }
ce1a9ee3
MB
1450}
1451
2c0d6100
GS
1452/* This was previously called lpphy_japan_filter */
1453static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel)
ce1a9ee3
MB
1454{
1455 struct b43_phy_lp *lpphy = dev->phy.lp;
2c0d6100 1456 u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
ce1a9ee3 1457
2c0d6100
GS
1458 if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
1459 b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
1460 if ((dev->phy.rev == 1) && (lpphy->rc_cap))
1461 lpphy_set_rc_cap(dev);
1462 } else {
1463 b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
1464 }
ce1a9ee3
MB
1465}
1466
7021f62a
GS
1467static void lpphy_set_tssi_mux(struct b43_wldev *dev, enum tssi_mux_mode mode)
1468{
1469 if (mode != TSSI_MUX_EXT) {
1470 b43_radio_set(dev, B2063_PA_SP1, 0x2);
1471 b43_phy_set(dev, B43_PHY_OFDM(0xF3), 0x1000);
1472 b43_radio_write(dev, B2063_PA_CTL10, 0x51);
1473 if (mode == TSSI_MUX_POSTPA) {
1474 b43_radio_mask(dev, B2063_PA_SP1, 0xFFFE);
1475 b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFC7);
1476 } else {
1477 b43_radio_maskset(dev, B2063_PA_SP1, 0xFFFE, 0x1);
1478 b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVRVAL,
1479 0xFFC7, 0x20);
1480 }
1481 } else {
1482 B43_WARN_ON(1);
1483 }
1484}
1485
1486static void lpphy_tx_pctl_init_hw(struct b43_wldev *dev)
1487{
1488 u16 tmp;
1489 int i;
1490
1491 //SPEC TODO Call LP PHY Clear TX Power offsets
1492 for (i = 0; i < 64; i++) {
1493 if (dev->phy.rev >= 2)
1494 b43_lptab_write(dev, B43_LPTAB32(7, i + 1), i);
1495 else
1496 b43_lptab_write(dev, B43_LPTAB32(10, i + 1), i);
1497 }
1498
1499 b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xFF00, 0xFF);
1500 b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0x8FFF, 0x5000);
1501 b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0xFFC0, 0x1F);
1502 if (dev->phy.rev < 2) {
1503 b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xEFFF);
1504 b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xDFFF, 0x2000);
1505 } else {
1506 b43_phy_mask(dev, B43_PHY_OFDM(0x103), 0xFFFE);
1507 b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFFB, 0x4);
1508 b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFEF, 0x10);
1509 b43_radio_maskset(dev, B2063_IQ_CALIB_CTL2, 0xF3, 0x1);
1510 lpphy_set_tssi_mux(dev, TSSI_MUX_POSTPA);
1511 }
1512 b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0x7FFF, 0x8000);
1513 b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF);
1514 b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA);
1515 b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
1516 (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE,
1517 B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
1518 b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF);
1519 b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
1520 (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE,
1521 B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW);
1522
1523 if (dev->phy.rev < 2) {
1524 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF, 0x1000);
1525 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xEFFF);
1526 } else {
1527 lpphy_set_tx_power_by_index(dev, 0x7F);
1528 }
1529
1530 b43_dummy_transmission(dev, true, true);
1531
1532 tmp = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_STAT);
1533 if (tmp & 0x8000) {
1534 b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI,
1535 0xFFC0, (tmp & 0xFF) - 32);
1536 }
1537
1538 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF);
1539
1540 // (SPEC?) TODO Set "Target TX frequency" variable to 0
1541 // SPEC FIXME "Set BB Multiplier to 0xE000" impossible - bb_mult is u8!
1542}
1543
1544static void lpphy_tx_pctl_init_sw(struct b43_wldev *dev)
1545{
1546 struct lpphy_tx_gains gains;
1547
1548 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
1549 gains.gm = 4;
1550 gains.pad = 12;
1551 gains.pga = 12;
1552 gains.dac = 0;
1553 } else {
1554 gains.gm = 7;
1555 gains.pad = 14;
1556 gains.pga = 15;
1557 gains.dac = 0;
1558 }
1559 lpphy_set_tx_gains(dev, gains);
1560 lpphy_set_bb_mult(dev, 150);
1561}
1562
ce1a9ee3
MB
1563/* Initialize TX power control */
1564static void lpphy_tx_pctl_init(struct b43_wldev *dev)
1565{
1566 if (0/*FIXME HWPCTL capable */) {
7021f62a 1567 lpphy_tx_pctl_init_hw(dev);
ce1a9ee3 1568 } else { /* This device is only software TX power control capable. */
7021f62a 1569 lpphy_tx_pctl_init_sw(dev);
ce1a9ee3
MB
1570 }
1571}
1572
2c0d6100
GS
1573static void lpphy_pr41573_workaround(struct b43_wldev *dev)
1574{
1575 struct b43_phy_lp *lpphy = dev->phy.lp;
1576 u32 *saved_tab;
1577 const unsigned int saved_tab_size = 256;
1578 enum b43_lpphy_txpctl_mode txpctl_mode;
1579 s8 tx_pwr_idx_over;
1580 u16 tssi_npt, tssi_idx;
1581
1582 saved_tab = kcalloc(saved_tab_size, sizeof(saved_tab[0]), GFP_KERNEL);
1583 if (!saved_tab) {
1584 b43err(dev->wl, "PR41573 failed. Out of memory!\n");
1585 return;
1586 }
1587
1588 lpphy_read_tx_pctl_mode_from_hardware(dev);
1589 txpctl_mode = lpphy->txpctl_mode;
1590 tx_pwr_idx_over = lpphy->tx_pwr_idx_over;
1591 tssi_npt = lpphy->tssi_npt;
1592 tssi_idx = lpphy->tssi_idx;
1593
1594 if (dev->phy.rev < 2) {
1595 b43_lptab_read_bulk(dev, B43_LPTAB32(10, 0x140),
1596 saved_tab_size, saved_tab);
1597 } else {
1598 b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
1599 saved_tab_size, saved_tab);
1600 }
1601 //FIXME PHY reset
1602 lpphy_table_init(dev); //FIXME is table init needed?
1603 lpphy_baseband_init(dev);
1604 lpphy_tx_pctl_init(dev);
1605 b43_lpphy_op_software_rfkill(dev, false);
1606 lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
1607 if (dev->phy.rev < 2) {
1608 b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0x140),
1609 saved_tab_size, saved_tab);
1610 } else {
1611 b43_lptab_write_bulk(dev, B43_LPTAB32(7, 0x140),
1612 saved_tab_size, saved_tab);
1613 }
1614 b43_write16(dev, B43_MMIO_CHANNEL, lpphy->channel);
1615 lpphy->tssi_npt = tssi_npt;
1616 lpphy->tssi_idx = tssi_idx;
1617 lpphy_set_analog_filter(dev, lpphy->channel);
1618 if (tx_pwr_idx_over != -1)
1619 lpphy_set_tx_power_by_index(dev, tx_pwr_idx_over);
1620 if (lpphy->rc_cap)
1621 lpphy_set_rc_cap(dev);
1622 b43_lpphy_op_set_rx_antenna(dev, lpphy->antenna);
1623 lpphy_set_tx_power_control(dev, txpctl_mode);
1624 kfree(saved_tab);
1625}
1626
1627struct lpphy_rx_iq_comp { u8 chan; s8 c1, c0; };
1628
1629static const struct lpphy_rx_iq_comp lpphy_5354_iq_table[] = {
1630 { .chan = 1, .c1 = -66, .c0 = 15, },
1631 { .chan = 2, .c1 = -66, .c0 = 15, },
1632 { .chan = 3, .c1 = -66, .c0 = 15, },
1633 { .chan = 4, .c1 = -66, .c0 = 15, },
1634 { .chan = 5, .c1 = -66, .c0 = 15, },
1635 { .chan = 6, .c1 = -66, .c0 = 15, },
1636 { .chan = 7, .c1 = -66, .c0 = 14, },
1637 { .chan = 8, .c1 = -66, .c0 = 14, },
1638 { .chan = 9, .c1 = -66, .c0 = 14, },
1639 { .chan = 10, .c1 = -66, .c0 = 14, },
1640 { .chan = 11, .c1 = -66, .c0 = 14, },
1641 { .chan = 12, .c1 = -66, .c0 = 13, },
1642 { .chan = 13, .c1 = -66, .c0 = 13, },
1643 { .chan = 14, .c1 = -66, .c0 = 13, },
1644};
1645
1646static const struct lpphy_rx_iq_comp lpphy_rev0_1_iq_table[] = {
1647 { .chan = 1, .c1 = -64, .c0 = 13, },
1648 { .chan = 2, .c1 = -64, .c0 = 13, },
1649 { .chan = 3, .c1 = -64, .c0 = 13, },
1650 { .chan = 4, .c1 = -64, .c0 = 13, },
1651 { .chan = 5, .c1 = -64, .c0 = 12, },
1652 { .chan = 6, .c1 = -64, .c0 = 12, },
1653 { .chan = 7, .c1 = -64, .c0 = 12, },
1654 { .chan = 8, .c1 = -64, .c0 = 12, },
1655 { .chan = 9, .c1 = -64, .c0 = 12, },
1656 { .chan = 10, .c1 = -64, .c0 = 11, },
1657 { .chan = 11, .c1 = -64, .c0 = 11, },
1658 { .chan = 12, .c1 = -64, .c0 = 11, },
1659 { .chan = 13, .c1 = -64, .c0 = 11, },
1660 { .chan = 14, .c1 = -64, .c0 = 10, },
1661 { .chan = 34, .c1 = -62, .c0 = 24, },
1662 { .chan = 38, .c1 = -62, .c0 = 24, },
1663 { .chan = 42, .c1 = -62, .c0 = 24, },
1664 { .chan = 46, .c1 = -62, .c0 = 23, },
1665 { .chan = 36, .c1 = -62, .c0 = 24, },
1666 { .chan = 40, .c1 = -62, .c0 = 24, },
1667 { .chan = 44, .c1 = -62, .c0 = 23, },
1668 { .chan = 48, .c1 = -62, .c0 = 23, },
1669 { .chan = 52, .c1 = -62, .c0 = 23, },
1670 { .chan = 56, .c1 = -62, .c0 = 22, },
1671 { .chan = 60, .c1 = -62, .c0 = 22, },
1672 { .chan = 64, .c1 = -62, .c0 = 22, },
1673 { .chan = 100, .c1 = -62, .c0 = 16, },
1674 { .chan = 104, .c1 = -62, .c0 = 16, },
1675 { .chan = 108, .c1 = -62, .c0 = 15, },
1676 { .chan = 112, .c1 = -62, .c0 = 14, },
1677 { .chan = 116, .c1 = -62, .c0 = 14, },
1678 { .chan = 120, .c1 = -62, .c0 = 13, },
1679 { .chan = 124, .c1 = -62, .c0 = 12, },
1680 { .chan = 128, .c1 = -62, .c0 = 12, },
1681 { .chan = 132, .c1 = -62, .c0 = 12, },
1682 { .chan = 136, .c1 = -62, .c0 = 11, },
1683 { .chan = 140, .c1 = -62, .c0 = 10, },
1684 { .chan = 149, .c1 = -61, .c0 = 9, },
1685 { .chan = 153, .c1 = -61, .c0 = 9, },
1686 { .chan = 157, .c1 = -61, .c0 = 9, },
1687 { .chan = 161, .c1 = -61, .c0 = 8, },
1688 { .chan = 165, .c1 = -61, .c0 = 8, },
1689 { .chan = 184, .c1 = -62, .c0 = 25, },
1690 { .chan = 188, .c1 = -62, .c0 = 25, },
1691 { .chan = 192, .c1 = -62, .c0 = 25, },
1692 { .chan = 196, .c1 = -62, .c0 = 25, },
1693 { .chan = 200, .c1 = -62, .c0 = 25, },
1694 { .chan = 204, .c1 = -62, .c0 = 25, },
1695 { .chan = 208, .c1 = -62, .c0 = 25, },
1696 { .chan = 212, .c1 = -62, .c0 = 25, },
1697 { .chan = 216, .c1 = -62, .c0 = 26, },
1698};
1699
1700static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = {
1701 .chan = 0,
1702 .c1 = -64,
1703 .c0 = 0,
1704};
1705
1706static u8 lpphy_nbits(s32 val)
1707{
1708 u32 tmp = abs(val);
1709 u8 nbits = 0;
1710
1711 while (tmp != 0) {
1712 nbits++;
1713 tmp >>= 1;
1714 }
1715
1716 return nbits;
1717}
1718
1719static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
1720{
1721 struct lpphy_iq_est iq_est;
1722 u16 c0, c1;
1723 int prod, ipwr, qpwr, prod_msb, q_msb, tmp1, tmp2, tmp3, tmp4, ret;
1724
1725 c1 = b43_phy_read(dev, B43_LPPHY_RX_COMP_COEFF_S);
1726 c0 = c1 >> 8;
1727 c1 |= 0xFF;
1728
1729 b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, 0x00C0);
1730 b43_phy_mask(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF);
1731
1732 ret = lpphy_rx_iq_est(dev, samples, 32, &iq_est);
1733 if (!ret)
1734 goto out;
1735
1736 prod = iq_est.iq_prod;
1737 ipwr = iq_est.i_pwr;
1738 qpwr = iq_est.q_pwr;
1739
1740 if (ipwr + qpwr < 2) {
1741 ret = 0;
1742 goto out;
1743 }
1744
1745 prod_msb = lpphy_nbits(prod);
1746 q_msb = lpphy_nbits(qpwr);
1747 tmp1 = prod_msb - 20;
1748
1749 if (tmp1 >= 0) {
1750 tmp3 = ((prod << (30 - prod_msb)) + (ipwr >> (1 + tmp1))) /
1751 (ipwr >> tmp1);
1752 } else {
1753 tmp3 = ((prod << (30 - prod_msb)) + (ipwr << (-1 - tmp1))) /
1754 (ipwr << -tmp1);
1755 }
1756
1757 tmp2 = q_msb - 11;
1758
1759 if (tmp2 >= 0)
1760 tmp4 = (qpwr << (31 - q_msb)) / (ipwr >> tmp2);
1761 else
1762 tmp4 = (qpwr << (31 - q_msb)) / (ipwr << -tmp2);
1763
1764 tmp4 -= tmp3 * tmp3;
1765 tmp4 = -int_sqrt(tmp4);
1766
1767 c0 = tmp3 >> 3;
1768 c1 = tmp4 >> 4;
1769
1770out:
1771 b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, c1);
1772 b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF, c0 << 8);
1773 return ret;
1774}
1775
1776/* Complex number using 2 32-bit signed integers */
1777typedef struct {s32 i, q;} lpphy_c32;
1778
1779static lpphy_c32 lpphy_cordic(int theta)
1780{
1781 u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304,
1782 58666, 29335, 14668, 7334, 3667, 1833, 917, 458,
1783 229, 115, 57, 29, };
1784 int i, tmp, signx = 1, angle = 0;
1785 lpphy_c32 ret = { .i = 39797, .q = 0, };
1786
1787 theta = clamp_t(int, theta, -180, 180);
1788
1789 if (theta > 90) {
1790 theta -= 180;
1791 signx = -1;
1792 } else if (theta < -90) {
1793 theta += 180;
1794 signx = -1;
1795 }
1796
1797 for (i = 0; i <= 17; i++) {
1798 if (theta > angle) {
1799 tmp = ret.i - (ret.q >> i);
1800 ret.q += ret.i >> i;
1801 ret.i = tmp;
1802 angle += arctg[i];
1803 } else {
1804 tmp = ret.i + (ret.q >> i);
1805 ret.q -= ret.i >> i;
1806 ret.i = tmp;
1807 angle -= arctg[i];
1808 }
1809 }
1810
1811 ret.i *= signx;
1812 ret.q *= signx;
1813
1814 return ret;
1815}
1816
1817static void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops,
1818 u16 wait)
1819{
1820 b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL,
1821 0xFFC0, samples - 1);
1822 if (loops != 0xFFFF)
1823 loops--;
1824 b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000, loops);
1825 b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL, 0x3F, wait << 6);
1826 b43_phy_set(dev, B43_LPPHY_A_PHY_CTL_ADDR, 0x1);
1827}
1828
1829//SPEC FIXME what does a negative freq mean?
1830static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max)
1831{
1832 struct b43_phy_lp *lpphy = dev->phy.lp;
1833 u16 buf[64];
1834 int i, samples = 0, angle = 0, rotation = (9 * freq) / 500;
1835 lpphy_c32 sample;
1836
1837 lpphy->tx_tone_freq = freq;
1838
1839 if (freq) {
1840 /* Find i for which abs(freq) integrally divides 20000 * i */
1841 for (i = 1; samples * abs(freq) != 20000 * i; i++) {
1842 samples = (20000 * i) / abs(freq);
1843 if(B43_WARN_ON(samples > 63))
1844 return;
1845 }
1846 } else {
1847 samples = 2;
1848 }
1849
1850 for (i = 0; i < samples; i++) {
1851 sample = lpphy_cordic(angle);
1852 angle += rotation;
1853 buf[i] = ((sample.i * max) & 0xFF) << 8;
1854 buf[i] |= (sample.q * max) & 0xFF;
1855 }
1856
1857 b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf);
1858
1859 lpphy_run_samples(dev, samples, 0xFFFF, 0);
1860}
1861
1862static void lpphy_stop_tx_tone(struct b43_wldev *dev)
1863{
1864 struct b43_phy_lp *lpphy = dev->phy.lp;
1865 int i;
1866
1867 lpphy->tx_tone_freq = 0;
1868
1869 b43_phy_mask(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000);
1870 for (i = 0; i < 31; i++) {
1871 if (!(b43_phy_read(dev, B43_LPPHY_A_PHY_CTL_ADDR) & 0x1))
1872 break;
1873 udelay(100);
1874 }
1875}
1876
1877
1878static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains,
1879 int mode, bool useindex, u8 index)
1880{
1881 //TODO
1882}
1883
1884static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
1885{
1886 struct b43_phy_lp *lpphy = dev->phy.lp;
1887 struct ssb_bus *bus = dev->dev->bus;
1888 struct lpphy_tx_gains gains, oldgains;
1889 int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
1890
1891 lpphy_read_tx_pctl_mode_from_hardware(dev);
1892 old_txpctl = lpphy->txpctl_mode;
1893 old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
1894 if (old_afe_ovr)
1895 oldgains = lpphy_get_tx_gains(dev);
1896 old_rf = b43_phy_read(dev, B43_LPPHY_RF_PWR_OVERRIDE) & 0xFF;
1897 old_bbmult = lpphy_get_bb_mult(dev);
1898
1899 lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
1900
1901 if (bus->chip_id == 0x4325 && bus->chip_rev == 0)
1902 lpphy_papd_cal(dev, gains, 0, 1, 30);
1903 else
1904 lpphy_papd_cal(dev, gains, 0, 1, 65);
1905
1906 if (old_afe_ovr)
1907 lpphy_set_tx_gains(dev, oldgains);
1908 lpphy_set_bb_mult(dev, old_bbmult);
1909 lpphy_set_tx_power_control(dev, old_txpctl);
1910 b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00, old_rf);
1911}
1912
1913static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
1914 bool rx, bool pa, struct lpphy_tx_gains *gains)
1915{
1916 struct b43_phy_lp *lpphy = dev->phy.lp;
1917 struct ssb_bus *bus = dev->dev->bus;
1918 const struct lpphy_rx_iq_comp *iqcomp = NULL;
1919 struct lpphy_tx_gains nogains, oldgains;
1920 u16 tmp;
1921 int i, ret;
1922
1923 memset(&nogains, 0, sizeof(nogains));
1924 memset(&oldgains, 0, sizeof(oldgains));
1925
1926 if (bus->chip_id == 0x5354) {
1927 for (i = 0; i < ARRAY_SIZE(lpphy_5354_iq_table); i++) {
1928 if (lpphy_5354_iq_table[i].chan == lpphy->channel) {
1929 iqcomp = &lpphy_5354_iq_table[i];
1930 }
1931 }
1932 } else if (dev->phy.rev >= 2) {
1933 iqcomp = &lpphy_rev2plus_iq_comp;
1934 } else {
1935 for (i = 0; i < ARRAY_SIZE(lpphy_rev0_1_iq_table); i++) {
1936 if (lpphy_rev0_1_iq_table[i].chan == lpphy->channel) {
1937 iqcomp = &lpphy_rev0_1_iq_table[i];
1938 }
1939 }
1940 }
1941
1942 if (B43_WARN_ON(!iqcomp))
1943 return 0;
1944
1945 b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, iqcomp->c1);
1946 b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S,
1947 0x00FF, iqcomp->c0 << 8);
1948
1949 if (noise) {
1950 tx = true;
1951 rx = false;
1952 pa = false;
1953 }
1954
1955 lpphy_set_trsw_over(dev, tx, rx);
1956
1957 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
1958 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
1959 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
1960 0xFFF7, pa << 3);
1961 } else {
1962 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
1963 b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
1964 0xFFDF, pa << 5);
1965 }
1966
1967 tmp = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
1968
1969 if (noise)
1970 lpphy_set_rx_gain(dev, 0x2D5D);
1971 else {
1972 if (tmp)
1973 oldgains = lpphy_get_tx_gains(dev);
1974 if (!gains)
1975 gains = &nogains;
1976 lpphy_set_tx_gains(dev, *gains);
1977 }
1978
1979 b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
1980 b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
1981 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
1982 b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
1983 lpphy_set_deaf(dev, false);
1984 if (noise)
1985 ret = lpphy_calc_rx_iq_comp(dev, 0xFFF0);
1986 else {
1987 lpphy_start_tx_tone(dev, 4000, 100);
1988 ret = lpphy_calc_rx_iq_comp(dev, 0x4000);
1989 lpphy_stop_tx_tone(dev);
1990 }
1991 lpphy_clear_deaf(dev, false);
1992 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFC);
1993 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7);
1994 b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFDF);
1995 if (!noise) {
1996 if (tmp)
1997 lpphy_set_tx_gains(dev, oldgains);
1998 else
1999 lpphy_disable_tx_gain_override(dev);
2000 }
2001 lpphy_disable_rx_gain_override(dev);
2002 b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
2003 b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xF7FF);
2004 return ret;
2005}
2006
2007static void lpphy_calibration(struct b43_wldev *dev)
2008{
2009 struct b43_phy_lp *lpphy = dev->phy.lp;
2010 enum b43_lpphy_txpctl_mode saved_pctl_mode;
2011 bool full_cal = false;
2012
2013 if (lpphy->full_calib_chan != lpphy->channel) {
2014 full_cal = true;
2015 lpphy->full_calib_chan = lpphy->channel;
2016 }
2017
2018 b43_mac_suspend(dev);
2019
2020 lpphy_btcoex_override(dev);
2021 if (dev->phy.rev >= 2)
2022 lpphy_save_dig_flt_state(dev);
2023 lpphy_read_tx_pctl_mode_from_hardware(dev);
2024 saved_pctl_mode = lpphy->txpctl_mode;
2025 lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
2026 //TODO Perform transmit power table I/Q LO calibration
2027 if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF))
2028 lpphy_pr41573_workaround(dev);
2029 if ((dev->phy.rev >= 2) && full_cal) {
2030 lpphy_papd_cal_txpwr(dev);
2031 }
2032 lpphy_set_tx_power_control(dev, saved_pctl_mode);
2033 if (dev->phy.rev >= 2)
2034 lpphy_restore_dig_flt_state(dev);
2035 lpphy_rx_iq_cal(dev, true, true, false, false, NULL);
2036
2037 b43_mac_enable(dev);
2038}
2039
e63e4363
MB
2040static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg)
2041{
0888707f
MB
2042 b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
2043 return b43_read16(dev, B43_MMIO_PHY_DATA);
e63e4363
MB
2044}
2045
2046static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
68ec5329 2047{
00fa928d
GS
2048 b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
2049 b43_write16(dev, B43_MMIO_PHY_DATA, value);
68ec5329
GS
2050}
2051
2052static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
2053 u16 set)
e63e4363 2054{
0888707f 2055 b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
68ec5329
GS
2056 b43_write16(dev, B43_MMIO_PHY_DATA,
2057 (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
e63e4363
MB
2058}
2059
2060static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
2061{
0888707f
MB
2062 /* Register 1 is a 32-bit register. */
2063 B43_WARN_ON(reg == 1);
2064 /* LP-PHY needs a special bit set for read access */
2065 if (dev->phy.rev < 2) {
2066 if (reg != 0x4001)
2067 reg |= 0x100;
2068 } else
2069 reg |= 0x200;
2070
2071 b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
2072 return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
e63e4363
MB
2073}
2074
2075static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
2076{
2077 /* Register 1 is a 32-bit register. */
2078 B43_WARN_ON(reg == 1);
2079
0888707f
MB
2080 b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
2081 b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
e63e4363
MB
2082}
2083
588f8377
GS
2084struct b206x_channel {
2085 u8 channel;
2086 u16 freq;
2087 u8 data[12];
2088};
2089
1e711bee
GS
2090static const struct b206x_channel b2062_chantbl[] = {
2091 { .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF,
2092 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2093 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2094 { .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF,
2095 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2096 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2097 { .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF,
2098 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2099 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2100 { .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF,
2101 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2102 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2103 { .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF,
2104 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2105 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2106 { .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF,
2107 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2108 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2109 { .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF,
2110 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2111 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2112 { .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF,
2113 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2114 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2115 { .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF,
2116 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2117 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2118 { .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF,
2119 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2120 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2121 { .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF,
2122 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2123 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2124 { .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF,
2125 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2126 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2127 { .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF,
2128 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2129 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2130 { .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF,
2131 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2132 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2133 { .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22,
2134 .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
2135 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2136 { .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11,
2137 .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2138 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2139 { .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11,
2140 .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2141 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2142 { .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00,
2143 .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2144 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2145 { .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11,
2146 .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2147 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2148 { .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11,
2149 .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
2150 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2151 { .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11,
2152 .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2153 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2154 { .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00,
2155 .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2156 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2157 { .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00,
2158 .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2159 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2160 { .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00,
2161 .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2162 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2163 { .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00,
2164 .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77,
2165 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2166 { .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00,
2167 .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77,
2168 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2169 { .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00,
2170 .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77,
2171 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2172 { .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00,
2173 .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
2174 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2175 { .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00,
2176 .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
2177 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2178 { .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00,
2179 .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
2180 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2181 { .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00,
2182 .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77,
2183 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2184 { .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00,
2185 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2186 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2187 { .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00,
2188 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2189 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2190 { .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00,
2191 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2192 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2193 { .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00,
2194 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2195 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2196 { .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00,
2197 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2198 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2199 { .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00,
2200 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2201 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2202 { .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00,
2203 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2204 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2205 { .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00,
2206 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2207 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2208 { .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00,
2209 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2210 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2211 { .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00,
2212 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2213 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2214 { .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00,
2215 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2216 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2217 { .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77,
2218 .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77,
2219 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2220 { .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77,
2221 .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
2222 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2223 { .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66,
2224 .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
2225 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2226 { .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66,
2227 .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
2228 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2229 { .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55,
2230 .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77,
2231 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2232 { .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55,
2233 .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
2234 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2235 { .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44,
2236 .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
2237 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2238 { .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44,
2239 .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77,
2240 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2241 { .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44,
2242 .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77,
2243 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2244};
2245
588f8377
GS
2246static const struct b206x_channel b2063_chantbl[] = {
2247 { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C,
2248 .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2249 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2250 .data[10] = 0x80, .data[11] = 0x70, },
2251 { .channel = 2, .freq = 2417, .data[0] = 0x6F, .data[1] = 0x3C,
2252 .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2253 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2254 .data[10] = 0x80, .data[11] = 0x70, },
2255 { .channel = 3, .freq = 2422, .data[0] = 0x6F, .data[1] = 0x3C,
2256 .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2257 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2258 .data[10] = 0x80, .data[11] = 0x70, },
2259 { .channel = 4, .freq = 2427, .data[0] = 0x6F, .data[1] = 0x2C,
2260 .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2261 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2262 .data[10] = 0x80, .data[11] = 0x70, },
2263 { .channel = 5, .freq = 2432, .data[0] = 0x6F, .data[1] = 0x2C,
2264 .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2265 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2266 .data[10] = 0x80, .data[11] = 0x70, },
2267 { .channel = 6, .freq = 2437, .data[0] = 0x6F, .data[1] = 0x2C,
2268 .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2269 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2270 .data[10] = 0x80, .data[11] = 0x70, },
2271 { .channel = 7, .freq = 2442, .data[0] = 0x6F, .data[1] = 0x2C,
2272 .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2273 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2274 .data[10] = 0x80, .data[11] = 0x70, },
2275 { .channel = 8, .freq = 2447, .data[0] = 0x6F, .data[1] = 0x2C,
2276 .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2277 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2278 .data[10] = 0x80, .data[11] = 0x70, },
2279 { .channel = 9, .freq = 2452, .data[0] = 0x6F, .data[1] = 0x1C,
2280 .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2281 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2282 .data[10] = 0x80, .data[11] = 0x70, },
2283 { .channel = 10, .freq = 2457, .data[0] = 0x6F, .data[1] = 0x1C,
2284 .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2285 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2286 .data[10] = 0x80, .data[11] = 0x70, },
2287 { .channel = 11, .freq = 2462, .data[0] = 0x6E, .data[1] = 0x1C,
2288 .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2289 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2290 .data[10] = 0x80, .data[11] = 0x70, },
2291 { .channel = 12, .freq = 2467, .data[0] = 0x6E, .data[1] = 0x1C,
2292 .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2293 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2294 .data[10] = 0x80, .data[11] = 0x70, },
2295 { .channel = 13, .freq = 2472, .data[0] = 0x6E, .data[1] = 0x1C,
2296 .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2297 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2298 .data[10] = 0x80, .data[11] = 0x70, },
2299 { .channel = 14, .freq = 2484, .data[0] = 0x6E, .data[1] = 0x0C,
2300 .data[2] = 0x0C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2301 .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2302 .data[10] = 0x80, .data[11] = 0x70, },
2303 { .channel = 34, .freq = 5170, .data[0] = 0x6A, .data[1] = 0x0C,
2304 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x02, .data[5] = 0x05,
2305 .data[6] = 0x0D, .data[7] = 0x0D, .data[8] = 0x77, .data[9] = 0x80,
2306 .data[10] = 0x20, .data[11] = 0x00, },
2307 { .channel = 36, .freq = 5180, .data[0] = 0x6A, .data[1] = 0x0C,
2308 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x05,
2309 .data[6] = 0x0D, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
2310 .data[10] = 0x20, .data[11] = 0x00, },
2311 { .channel = 38, .freq = 5190, .data[0] = 0x6A, .data[1] = 0x0C,
2312 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
2313 .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
2314 .data[10] = 0x20, .data[11] = 0x00, },
2315 { .channel = 40, .freq = 5200, .data[0] = 0x69, .data[1] = 0x0C,
2316 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
2317 .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
2318 .data[10] = 0x20, .data[11] = 0x00, },
2319 { .channel = 42, .freq = 5210, .data[0] = 0x69, .data[1] = 0x0C,
2320 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
2321 .data[6] = 0x0B, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
2322 .data[10] = 0x20, .data[11] = 0x00, },
2323 { .channel = 44, .freq = 5220, .data[0] = 0x69, .data[1] = 0x0C,
2324 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x04,
2325 .data[6] = 0x0B, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
2326 .data[10] = 0x20, .data[11] = 0x00, },
2327 { .channel = 46, .freq = 5230, .data[0] = 0x69, .data[1] = 0x0C,
2328 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
2329 .data[6] = 0x0A, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
2330 .data[10] = 0x20, .data[11] = 0x00, },
2331 { .channel = 48, .freq = 5240, .data[0] = 0x69, .data[1] = 0x0C,
2332 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
2333 .data[6] = 0x0A, .data[7] = 0x0A, .data[8] = 0x77, .data[9] = 0x60,
2334 .data[10] = 0x20, .data[11] = 0x00, },
2335 { .channel = 52, .freq = 5260, .data[0] = 0x68, .data[1] = 0x0C,
2336 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x02,
2337 .data[6] = 0x09, .data[7] = 0x09, .data[8] = 0x77, .data[9] = 0x60,
2338 .data[10] = 0x20, .data[11] = 0x00, },
2339 { .channel = 56, .freq = 5280, .data[0] = 0x68, .data[1] = 0x0C,
2340 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
2341 .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
2342 .data[10] = 0x10, .data[11] = 0x00, },
2343 { .channel = 60, .freq = 5300, .data[0] = 0x68, .data[1] = 0x0C,
2344 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
2345 .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
2346 .data[10] = 0x10, .data[11] = 0x00, },
2347 { .channel = 64, .freq = 5320, .data[0] = 0x67, .data[1] = 0x0C,
2348 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2349 .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
2350 .data[10] = 0x10, .data[11] = 0x00, },
2351 { .channel = 100, .freq = 5500, .data[0] = 0x64, .data[1] = 0x0C,
2352 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2353 .data[6] = 0x02, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
2354 .data[10] = 0x00, .data[11] = 0x00, },
2355 { .channel = 104, .freq = 5520, .data[0] = 0x64, .data[1] = 0x0C,
2356 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2357 .data[6] = 0x01, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
2358 .data[10] = 0x00, .data[11] = 0x00, },
2359 { .channel = 108, .freq = 5540, .data[0] = 0x63, .data[1] = 0x0C,
2360 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2361 .data[6] = 0x01, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
2362 .data[10] = 0x00, .data[11] = 0x00, },
2363 { .channel = 112, .freq = 5560, .data[0] = 0x63, .data[1] = 0x0C,
2364 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2365 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
2366 .data[10] = 0x00, .data[11] = 0x00, },
2367 { .channel = 116, .freq = 5580, .data[0] = 0x62, .data[1] = 0x0C,
2368 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2369 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
2370 .data[10] = 0x00, .data[11] = 0x00, },
2371 { .channel = 120, .freq = 5600, .data[0] = 0x62, .data[1] = 0x0C,
2372 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2373 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2374 .data[10] = 0x00, .data[11] = 0x00, },
2375 { .channel = 124, .freq = 5620, .data[0] = 0x62, .data[1] = 0x0C,
2376 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2377 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2378 .data[10] = 0x00, .data[11] = 0x00, },
2379 { .channel = 128, .freq = 5640, .data[0] = 0x61, .data[1] = 0x0C,
2380 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2381 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2382 .data[10] = 0x00, .data[11] = 0x00, },
2383 { .channel = 132, .freq = 5660, .data[0] = 0x61, .data[1] = 0x0C,
2384 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2385 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2386 .data[10] = 0x00, .data[11] = 0x00, },
2387 { .channel = 136, .freq = 5680, .data[0] = 0x61, .data[1] = 0x0C,
2388 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2389 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2390 .data[10] = 0x00, .data[11] = 0x00, },
2391 { .channel = 140, .freq = 5700, .data[0] = 0x60, .data[1] = 0x0C,
2392 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2393 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2394 .data[10] = 0x00, .data[11] = 0x00, },
2395 { .channel = 149, .freq = 5745, .data[0] = 0x60, .data[1] = 0x0C,
2396 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2397 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2398 .data[10] = 0x00, .data[11] = 0x00, },
2399 { .channel = 153, .freq = 5765, .data[0] = 0x60, .data[1] = 0x0C,
2400 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2401 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2402 .data[10] = 0x00, .data[11] = 0x00, },
2403 { .channel = 157, .freq = 5785, .data[0] = 0x60, .data[1] = 0x0C,
2404 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2405 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2406 .data[10] = 0x00, .data[11] = 0x00, },
2407 { .channel = 161, .freq = 5805, .data[0] = 0x60, .data[1] = 0x0C,
2408 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2409 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2410 .data[10] = 0x00, .data[11] = 0x00, },
2411 { .channel = 165, .freq = 5825, .data[0] = 0x60, .data[1] = 0x0C,
2412 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2413 .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2414 .data[10] = 0x00, .data[11] = 0x00, },
2415 { .channel = 184, .freq = 4920, .data[0] = 0x6E, .data[1] = 0x0C,
2416 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0E,
2417 .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xC0,
2418 .data[10] = 0x50, .data[11] = 0x00, },
2419 { .channel = 188, .freq = 4940, .data[0] = 0x6E, .data[1] = 0x0C,
2420 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0D,
2421 .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
2422 .data[10] = 0x50, .data[11] = 0x00, },
2423 { .channel = 192, .freq = 4960, .data[0] = 0x6E, .data[1] = 0x0C,
2424 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
2425 .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
2426 .data[10] = 0x50, .data[11] = 0x00, },
2427 { .channel = 196, .freq = 4980, .data[0] = 0x6D, .data[1] = 0x0C,
2428 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
2429 .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
2430 .data[10] = 0x40, .data[11] = 0x00, },
2431 { .channel = 200, .freq = 5000, .data[0] = 0x6D, .data[1] = 0x0C,
2432 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0B,
2433 .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
2434 .data[10] = 0x40, .data[11] = 0x00, },
2435 { .channel = 204, .freq = 5020, .data[0] = 0x6D, .data[1] = 0x0C,
2436 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0A,
2437 .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
2438 .data[10] = 0x40, .data[11] = 0x00, },
2439 { .channel = 208, .freq = 5040, .data[0] = 0x6C, .data[1] = 0x0C,
2440 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x07, .data[5] = 0x09,
2441 .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
2442 .data[10] = 0x40, .data[11] = 0x00, },
2443 { .channel = 212, .freq = 5060, .data[0] = 0x6C, .data[1] = 0x0C,
2444 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x06, .data[5] = 0x08,
2445 .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
2446 .data[10] = 0x40, .data[11] = 0x00, },
2447 { .channel = 216, .freq = 5080, .data[0] = 0x6C, .data[1] = 0x0C,
2448 .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x05, .data[5] = 0x08,
2449 .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
2450 .data[10] = 0x40, .data[11] = 0x00, },
2451};
2452
1e711bee 2453static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
588f8377 2454{
1e711bee
GS
2455 struct ssb_bus *bus = dev->dev->bus;
2456
2457 b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
2458 udelay(20);
2459 if (bus->chip_id == 0x5354) {
2460 b43_radio_write(dev, B2062_N_COMM1, 4);
2461 b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4);
2462 } else {
2463 b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0);
2464 }
2465 udelay(5);
2466}
2467
2468static void lpphy_b2062_vco_calib(struct b43_wldev *dev)
2469{
68ec5329
GS
2470 b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x42);
2471 b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x62);
1e711bee
GS
2472 udelay(200);
2473}
2474
2475static int lpphy_b2062_tune(struct b43_wldev *dev,
2476 unsigned int channel)
2477{
2478 struct b43_phy_lp *lpphy = dev->phy.lp;
2479 struct ssb_bus *bus = dev->dev->bus;
5269102e 2480 const struct b206x_channel *chandata = NULL;
1e711bee
GS
2481 u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
2482 u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
2483 int i, err = 0;
2484
5269102e
GS
2485 for (i = 0; i < ARRAY_SIZE(b2062_chantbl); i++) {
2486 if (b2062_chantbl[i].channel == channel) {
2487 chandata = &b2062_chantbl[i];
1e711bee
GS
2488 break;
2489 }
2490 }
2491
2492 if (B43_WARN_ON(!chandata))
2493 return -EINVAL;
2494
2495 b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04);
2496 b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]);
2497 b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]);
2498 b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]);
2499 b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]);
2500 b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]);
2501 b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]);
2502 b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]);
2503 b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]);
2504 b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]);
2505
2506 tmp1 = crystal_freq / 1000;
2507 tmp2 = lpphy->pdiv * 1000;
2508 b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xCC);
2509 b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0x07);
2510 lpphy_b2062_reset_pll_bias(dev);
2511 tmp3 = tmp2 * channel2freq_lp(channel);
2512 if (channel2freq_lp(channel) < 4000)
2513 tmp3 *= 2;
2514 tmp4 = 48 * tmp1;
2515 tmp6 = tmp3 / tmp4;
2516 tmp7 = tmp3 % tmp4;
2517 b43_radio_write(dev, B2062_S_RFPLL_CTL26, tmp6);
2518 tmp5 = tmp7 * 0x100;
2519 tmp6 = tmp5 / tmp4;
2520 tmp7 = tmp5 % tmp4;
055114a3
GS
2521 b43_radio_write(dev, B2062_S_RFPLL_CTL27, tmp6);
2522 tmp5 = tmp7 * 0x100;
2523 tmp6 = tmp5 / tmp4;
2524 tmp7 = tmp5 % tmp4;
1e711bee
GS
2525 b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6);
2526 tmp5 = tmp7 * 0x100;
2527 tmp6 = tmp5 / tmp4;
2528 tmp7 = tmp5 % tmp4;
2529 b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4));
68ec5329 2530 tmp8 = b43_radio_read(dev, B2062_S_RFPLL_CTL19);
1e711bee 2531 tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1);
ed07c4b3 2532 b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16);
1e711bee
GS
2533 b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF);
2534
2535 lpphy_b2062_vco_calib(dev);
2536 if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) {
2537 b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xFC);
2538 b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0);
2539 lpphy_b2062_reset_pll_bias(dev);
2540 lpphy_b2062_vco_calib(dev);
2541 if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10)
96909e97 2542 err = -EIO;
1e711bee
GS
2543 }
2544
2545 b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04);
2546 return err;
2547}
2548
588f8377
GS
2549static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
2550{
2551 u16 tmp;
2552
68ec5329
GS
2553 b43_radio_mask(dev, B2063_PLL_SP1, ~0x40);
2554 tmp = b43_radio_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8;
2555 b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp);
588f8377 2556 udelay(1);
68ec5329 2557 b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4);
588f8377 2558 udelay(1);
68ec5329 2559 b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6);
588f8377 2560 udelay(1);
68ec5329 2561 b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7);
588f8377 2562 udelay(300);
68ec5329 2563 b43_radio_set(dev, B2063_PLL_SP1, 0x40);
588f8377
GS
2564}
2565
1e711bee
GS
2566static int lpphy_b2063_tune(struct b43_wldev *dev,
2567 unsigned int channel)
588f8377
GS
2568{
2569 struct ssb_bus *bus = dev->dev->bus;
2570
2571 static const struct b206x_channel *chandata = NULL;
2572 u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
2573 u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count;
2574 u16 old_comm15, scale;
2575 u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
2576 int i, div = (crystal_freq <= 26000000 ? 1 : 2);
2577
2578 for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) {
2579 if (b2063_chantbl[i].channel == channel) {
2580 chandata = &b2063_chantbl[i];
2581 break;
2582 }
2583 }
2584
2585 if (B43_WARN_ON(!chandata))
1e711bee 2586 return -EINVAL;
588f8377
GS
2587
2588 b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]);
2589 b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]);
2590 b43_radio_write(dev, B2063_LOGEN_BUF2, chandata->data[2]);
2591 b43_radio_write(dev, B2063_LOGEN_RCCR1, chandata->data[3]);
2592 b43_radio_write(dev, B2063_A_RX_1ST3, chandata->data[4]);
2593 b43_radio_write(dev, B2063_A_RX_2ND1, chandata->data[5]);
2594 b43_radio_write(dev, B2063_A_RX_2ND4, chandata->data[6]);
2595 b43_radio_write(dev, B2063_A_RX_2ND7, chandata->data[7]);
2596 b43_radio_write(dev, B2063_A_RX_PS6, chandata->data[8]);
2597 b43_radio_write(dev, B2063_TX_RF_CTL2, chandata->data[9]);
2598 b43_radio_write(dev, B2063_TX_RF_CTL5, chandata->data[10]);
2599 b43_radio_write(dev, B2063_PA_CTL11, chandata->data[11]);
2600
2601 old_comm15 = b43_radio_read(dev, B2063_COMM15);
2602 b43_radio_set(dev, B2063_COMM15, 0x1E);
2603
2604 if (chandata->freq > 4000) /* spec says 2484, but 4000 is safer */
2605 vco_freq = chandata->freq << 1;
2606 else
2607 vco_freq = chandata->freq << 2;
2608
2609 freqref = crystal_freq * 3;
2610 val1 = lpphy_qdiv_roundup(crystal_freq, 1000000, 16);
2611 val2 = lpphy_qdiv_roundup(crystal_freq, 1000000 * div, 16);
2612 val3 = lpphy_qdiv_roundup(vco_freq, 3, 16);
2613 timeout = ((((8 * crystal_freq) / (div * 5000000)) + 1) >> 1) - 1;
2614 b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB3, 0x2);
2615 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB6,
2616 0xFFF8, timeout >> 2);
2617 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
2618 0xFF9F,timeout << 5);
2619
2620 timeoutref = ((((8 * crystal_freq) / (div * (timeout + 1))) +
2621 999999) / 1000000) + 1;
2622 b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB5, timeoutref);
2623
2624 count = lpphy_qdiv_roundup(val3, val2 + 16, 16);
2625 count *= (timeout + 1) * (timeoutref + 1);
2626 count--;
2627 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
2628 0xF0, count >> 8);
2629 b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB8, count & 0xFF);
2630
2631 tmp1 = ((val3 * 62500) / freqref) << 4;
2632 tmp2 = ((val3 * 62500) % freqref) << 4;
2633 while (tmp2 >= freqref) {
2634 tmp1++;
2635 tmp2 -= freqref;
2636 }
2637 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG1, 0xFFE0, tmp1 >> 4);
2638 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFE0F, tmp1 << 4);
2639 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFFF0, tmp1 >> 16);
2640 b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG3, (tmp2 >> 8) & 0xFF);
2641 b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG4, tmp2 & 0xFF);
2642
2643 b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF1, 0xB9);
2644 b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF2, 0x88);
2645 b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF3, 0x28);
2646 b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF4, 0x63);
2647
2648 tmp3 = ((41 * (val3 - 3000)) /1200) + 27;
2649 tmp4 = lpphy_qdiv_roundup(132000 * tmp1, 8451, 16);
2650
2651 if ((tmp4 + tmp3 - 1) / tmp3 > 60) {
2652 scale = 1;
2653 tmp5 = ((tmp4 + tmp3) / (tmp3 << 1)) - 8;
2654 } else {
2655 scale = 0;
2656 tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8;
2657 }
68ec5329
GS
2658 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5);
2659 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6);
588f8377
GS
2660
2661 tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16);
2662 tmp6 *= (tmp5 * 8) * (scale + 1);
2663 if (tmp6 > 150)
2664 tmp6 = 0;
2665
68ec5329
GS
2666 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6);
2667 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5);
588f8377 2668
68ec5329 2669 b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4);
588f8377 2670 if (crystal_freq > 26000000)
68ec5329 2671 b43_radio_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2);
588f8377 2672 else
68ec5329 2673 b43_radio_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD);
588f8377
GS
2674
2675 if (val1 == 45)
68ec5329 2676 b43_radio_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2);
588f8377 2677 else
68ec5329 2678 b43_radio_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD);
588f8377 2679
68ec5329 2680 b43_radio_set(dev, B2063_PLL_SP2, 0x3);
588f8377 2681 udelay(1);
68ec5329 2682 b43_radio_mask(dev, B2063_PLL_SP2, 0xFFFC);
588f8377
GS
2683 lpphy_b2063_vco_calib(dev);
2684 b43_radio_write(dev, B2063_COMM15, old_comm15);
1e711bee
GS
2685
2686 return 0;
588f8377
GS
2687}
2688
e63e4363
MB
2689static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
2690 unsigned int new_channel)
2691{
68ec5329 2692 struct b43_phy_lp *lpphy = dev->phy.lp;
1e711bee
GS
2693 int err;
2694
588f8377 2695 if (dev->phy.radio_ver == 0x2063) {
1e711bee
GS
2696 err = lpphy_b2063_tune(dev, new_channel);
2697 if (err)
2698 return err;
588f8377 2699 } else {
1e711bee
GS
2700 err = lpphy_b2062_tune(dev, new_channel);
2701 if (err)
2702 return err;
5791ce18 2703 lpphy_set_analog_filter(dev, new_channel);
0c61bb9a 2704 lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel));
588f8377
GS
2705 }
2706
68ec5329
GS
2707 lpphy->channel = new_channel;
2708 b43_write16(dev, B43_MMIO_CHANNEL, new_channel);
2709
e63e4363
MB
2710 return 0;
2711}
2712
588f8377 2713static int b43_lpphy_op_init(struct b43_wldev *dev)
e63e4363 2714{
96909e97
GS
2715 int err;
2716
588f8377
GS
2717 lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs?
2718 lpphy_baseband_init(dev);
2719 lpphy_radio_init(dev);
2720 lpphy_calibrate_rc(dev);
68ec5329 2721 err = b43_lpphy_op_switch_channel(dev, 7);
96909e97 2722 if (err) {
68ec5329 2723 b43dbg(dev->wl, "Switch to channel 7 failed, error = %d.\n",
96909e97
GS
2724 err);
2725 }
588f8377
GS
2726 lpphy_tx_pctl_init(dev);
2727 lpphy_calibration(dev);
2728 //TODO ACI init
2729
2730 return 0;
e63e4363
MB
2731}
2732
e63e4363
MB
2733static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
2734{
2735 //TODO
2736}
2737
2738static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
2739 bool ignore_tssi)
2740{
2741 //TODO
2742 return B43_TXPWR_RES_DONE;
2743}
2744
9308779a
TI
2745void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
2746{
2747 if (on) {
2748 b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xfff8);
2749 } else {
2750 b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0x0007);
2751 b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x0007);
2752 }
2753}
2754
2c0d6100
GS
2755static void b43_lpphy_op_pwork_15sec(struct b43_wldev *dev)
2756{
2757 //TODO
2758}
2759
e63e4363
MB
2760const struct b43_phy_operations b43_phyops_lp = {
2761 .allocate = b43_lpphy_op_allocate,
fb11137a
MB
2762 .free = b43_lpphy_op_free,
2763 .prepare_structs = b43_lpphy_op_prepare_structs,
e63e4363 2764 .init = b43_lpphy_op_init,
e63e4363
MB
2765 .phy_read = b43_lpphy_op_read,
2766 .phy_write = b43_lpphy_op_write,
68ec5329 2767 .phy_maskset = b43_lpphy_op_maskset,
e63e4363
MB
2768 .radio_read = b43_lpphy_op_radio_read,
2769 .radio_write = b43_lpphy_op_radio_write,
2770 .software_rfkill = b43_lpphy_op_software_rfkill,
9308779a 2771 .switch_analog = b43_lpphy_op_switch_analog,
e63e4363
MB
2772 .switch_channel = b43_lpphy_op_switch_channel,
2773 .get_default_chan = b43_lpphy_op_get_default_chan,
2774 .set_rx_antenna = b43_lpphy_op_set_rx_antenna,
2775 .recalc_txpower = b43_lpphy_op_recalc_txpower,
2776 .adjust_txpower = b43_lpphy_op_adjust_txpower,
2c0d6100
GS
2777 .pwork_15sec = b43_lpphy_op_pwork_15sec,
2778 .pwork_60sec = lpphy_calibration,
e63e4363 2779};