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