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