Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
phy_lp.c
Go to the documentation of this file.
1 /*
2 
3  Broadcom B43 wireless driver
4  IEEE 802.11a/g LP-PHY driver
5 
6  Copyright (c) 2008-2009 Michael Buesch <[email protected]>
7  Copyright (c) 2009 Gábor Stefanik <[email protected]>
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));
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 ssb_sprom *sprom = dev->dev->bus_sprom;
89  struct b43_phy_lp *lpphy = dev->phy.lp;
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 = sprom->tri2g;
96  lpphy->bx_arch = sprom->bxa2g;
97  lpphy->rx_pwr_offset = sprom->rxpo2g;
98  lpphy->rssi_vf = sprom->rssismf2g;
99  lpphy->rssi_vc = sprom->rssismc2g;
100  lpphy->rssi_gs = sprom->rssisav2g;
101  lpphy->txpa[0] = sprom->pa0b0;
102  lpphy->txpa[1] = sprom->pa0b1;
103  lpphy->txpa[2] = sprom->pa0b2;
104  maxpwr = sprom->maxpwr_bg;
105  lpphy->max_tx_pwr_med_band = maxpwr;
106  cckpo = 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(sprom->revision < 8);
113  ofdmpo = 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 = 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 = sprom->tri5gl;
135  lpphy->tx_isolation_med_band = sprom->tri5g;
136  lpphy->tx_isolation_hi_band = sprom->tri5gh;
137  lpphy->bx_arch = sprom->bxa5g;
138  lpphy->rx_pwr_offset = sprom->rxpo5g;
139  lpphy->rssi_vf = sprom->rssismf5g;
140  lpphy->rssi_vc = sprom->rssismc5g;
141  lpphy->rssi_gs = sprom->rssisav5g;
142  lpphy->txpa[0] = sprom->pa1b0;
143  lpphy->txpa[1] = sprom->pa1b1;
144  lpphy->txpa[2] = sprom->pa1b2;
145  lpphy->txpal[0] = sprom->pa1lob0;
146  lpphy->txpal[1] = sprom->pa1lob1;
147  lpphy->txpal[2] = sprom->pa1lob2;
148  lpphy->txpah[0] = sprom->pa1hib0;
149  lpphy->txpah[1] = sprom->pa1hib1;
150  lpphy->txpah[2] = sprom->pa1hib2;
151  maxpwr = sprom->maxpwr_al;
152  ofdmpo = 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 = sprom->maxpwr_a;
159  ofdmpo = 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 = sprom->maxpwr_ah;
166  ofdmpo = 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)
206  else
208 
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->dev->sdev->bus;
218  struct ssb_sprom *sprom = dev->dev->bus_sprom;
219  struct b43_phy_lp *lpphy = dev->phy.lp;
220  u16 tmp, tmp2;
221 
222  b43_phy_mask(dev, B43_LPPHY_AFE_DAC_CTL, 0xF7FF);
227  b43_phy_set(dev, B43_LPPHY_AFE_DAC_CTL, 0x0004);
228  b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x0078);
229  b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
231  b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_0, 0xFFF8, 0x0004);
232  b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5400);
233  b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2400);
234  b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
235  b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006);
236  b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE);
237  b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005);
238  b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0x0180);
239  b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3C00);
240  b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005);
241  b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A);
242  b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3);
243  b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
245  0xFF00, lpphy->rx_pwr_offset);
246  if ((sprom->boardflags_lo & B43_BFL_FEM) &&
247  ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ||
248  (sprom->boardflags_hi & B43_BFH_PAREF))) {
250  ssb_pmu_set_ldo_paref(&bus->chipco, true);
251  if (dev->phy.rev == 0) {
253  0xFFCF, 0x0010);
254  }
255  b43_lptab_write(dev, B43_LPTAB16(11, 7), 60);
256  } else {
257  ssb_pmu_set_ldo_paref(&bus->chipco, false);
259  0xFFCF, 0x0020);
260  b43_lptab_write(dev, B43_LPTAB16(11, 7), 100);
261  }
262  tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000;
264  if (sprom->boardflags_hi & B43_BFH_RSSIINV)
265  b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA);
266  else
267  b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA);
268  b43_lptab_write(dev, B43_LPTAB16(11, 1), 24);
270  0xFFF9, (lpphy->bx_arch << 1));
271  if (dev->phy.rev == 1 &&
272  (sprom->boardflags_hi & B43_BFH_FEM_BT)) {
273  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
274  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900);
275  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
276  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
277  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x000A);
278  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0400);
279  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x000A);
280  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0B00);
281  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xFFC0, 0x000A);
282  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xC0FF, 0x0900);
283  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xFFC0, 0x000A);
284  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xC0FF, 0x0B00);
285  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xFFC0, 0x000A);
286  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xC0FF, 0x0900);
287  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A);
288  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00);
289  } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ ||
290  (dev->dev->board_type == 0x048A) || ((dev->phy.rev == 0) &&
291  (sprom->boardflags_lo & B43_BFL_FEM))) {
292  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001);
293  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400);
294  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001);
295  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0500);
296  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
297  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0800);
298  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
299  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00);
300  } else if (dev->phy.rev == 1 ||
301  (sprom->boardflags_lo & B43_BFL_FEM)) {
302  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004);
303  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800);
304  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004);
305  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0C00);
306  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
307  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0100);
308  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
309  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0300);
310  } else {
311  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
312  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0900);
313  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
314  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
315  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0006);
316  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0500);
317  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006);
318  b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700);
319  }
320  if (dev->phy.rev == 1 && (sprom->boardflags_hi & B43_BFH_PAREF)) {
325  }
326  if ((sprom->boardflags_hi & B43_BFH_FEM_BT) &&
327  (dev->dev->chip_id == 0x5354) &&
328  (dev->dev->chip_pkg == SSB_CHIPPACK_BCM4712S)) {
329  b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006);
330  b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005);
331  b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF);
332  //FIXME the Broadcom driver caches & delays this HF write!
334  }
335  if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
336  b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000);
337  b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0040);
338  b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0xA400);
339  b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0x0B00);
340  b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x0007);
341  b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFF8, 0x0003);
342  b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFC7, 0x0020);
344  } else { /* 5GHz */
345  b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0x7FFF);
346  b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFBF);
347  }
348  if (dev->phy.rev == 1) {
350  tmp2 = (tmp & 0x03E0) >> 5;
351  tmp2 |= tmp2 << 5;
352  b43_phy_write(dev, B43_LPPHY_4C3, tmp2);
354  tmp2 = (tmp & 0x1F00) >> 8;
355  tmp2 |= tmp2 << 5;
356  b43_phy_write(dev, B43_LPPHY_4C4, tmp2);
358  tmp2 = tmp & 0x00FF;
359  tmp2 |= tmp << 8;
360  b43_phy_write(dev, B43_LPPHY_4C5, tmp2);
361  }
362 }
363 
364 static void lpphy_save_dig_flt_state(struct b43_wldev *dev)
365 {
366  static const u16 addr[] = {
367  B43_PHY_OFDM(0xC1),
368  B43_PHY_OFDM(0xC2),
369  B43_PHY_OFDM(0xC3),
370  B43_PHY_OFDM(0xC4),
371  B43_PHY_OFDM(0xC5),
372  B43_PHY_OFDM(0xC6),
373  B43_PHY_OFDM(0xC7),
374  B43_PHY_OFDM(0xC8),
375  B43_PHY_OFDM(0xCF),
376  };
377 
378  static const u16 coefs[] = {
379  0xDE5E, 0xE832, 0xE331, 0x4D26,
380  0x0026, 0x1420, 0x0020, 0xFE08,
381  0x0008,
382  };
383 
384  struct b43_phy_lp *lpphy = dev->phy.lp;
385  int i;
386 
387  for (i = 0; i < ARRAY_SIZE(addr); i++) {
388  lpphy->dig_flt_state[i] = b43_phy_read(dev, addr[i]);
389  b43_phy_write(dev, addr[i], coefs[i]);
390  }
391 }
392 
393 static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
394 {
395  static const u16 addr[] = {
396  B43_PHY_OFDM(0xC1),
397  B43_PHY_OFDM(0xC2),
398  B43_PHY_OFDM(0xC3),
399  B43_PHY_OFDM(0xC4),
400  B43_PHY_OFDM(0xC5),
401  B43_PHY_OFDM(0xC6),
402  B43_PHY_OFDM(0xC7),
403  B43_PHY_OFDM(0xC8),
404  B43_PHY_OFDM(0xCF),
405  };
406 
407  struct b43_phy_lp *lpphy = dev->phy.lp;
408  int i;
409 
410  for (i = 0; i < ARRAY_SIZE(addr); i++)
411  b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]);
412 }
413 
414 static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
415 {
416  struct b43_phy_lp *lpphy = dev->phy.lp;
417 
419  b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0x8800);
424  b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0);
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 (dev->dev->board_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);
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);
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 ((dev->dev->chip_id == 0x4325) && (dev->dev->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 ((dev->dev->chip_id == 0x4325) && (dev->dev->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) {
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);
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);
488  b43_phy_set(dev, B43_LPPHY_RESET_CTL, 0x44);
492  0x2000 | ((u16)lpphy->rssi_gs << 10) |
493  ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf);
494 
495  if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
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 
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->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 
543 
548  b43_radio_write(dev, B2062_N_PDN_CTL0, 0x40);
550  b43_radio_write(dev, B2062_N_CALIB_TS, 0x10);
552  if (dev->phy.rev > 0) {
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;
573  }
574 
575  tmp = (((800000000 * lpphy->pdiv + crystalfreq) /
576  (2 * crystalfreq)) - 8) & 0xFF;
578 
579  tmp = (((100 * crystalfreq + 16000000 * lpphy->pdiv) /
580  (32000000 * lpphy->pdiv)) - 1) & 0xFF;
582 
583  tmp = (((2 * crystalfreq + 1000000 * lpphy->pdiv) /
584  (2000000 * lpphy->pdiv)) - 1) & 0xFF;
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 
601  ((u16)(fd->data[1]) << 4) | fd->data[0]);
603  ((u16)(fd->data[3]) << 4) | fd->data[2]);
606 }
607 
608 /* Initialize the 2063 radio. */
609 static void lpphy_2063_init(struct b43_wldev *dev)
610 {
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 
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. */
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->dev->chip_id == 0x4325) {
701  // TODO SSB PMU recalibration
702  }
703  }
704 }
705 
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 
718  max_t(u8, lpphy->rc_cap - 4, 0x80));
719  b43_radio_write(dev, B2062_N_TX_CTL_A, rc_cap | 0x80);
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 = true;
740  else
741  lpphy->crs_sys_disable = true;
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 = false;
751  else
752  lpphy->crs_sys_disable = false;
753 
754  if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) {
755  if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
757  0xFF1F, 0x60);
758  else
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);
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);
798 }
799 
800 static void lpphy_restore_crs(struct b43_wldev *dev, bool user)
801 {
802  lpphy_clear_deaf(dev, user);
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 {
814  if (dev->phy.rev >= 2) {
816  if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
818  b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
819  }
820  } else {
822  }
823 }
824 
825 static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
826 {
830  if (dev->phy.rev >= 2) {
832  if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
834  b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
835  }
836  } else {
838  }
839 }
840 
841 static void lpphy_disable_tx_gain_override(struct b43_wldev *dev)
842 {
843  if (dev->phy.rev < 2)
845  else {
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)
856  else {
858  b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x4000);
859  }
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,
872  gains.gm = tmp & 0x0007;
873  gains.pga = (tmp & 0x0078) >> 3;
874  gains.pad = (tmp & 0x780) >> 7;
875  } else {
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;
911  0xF800, rf_gain);
912  } else {
913  pa_gain = lpphy_get_pa_gain(dev);
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);
939  0xFBFF, ext_lna << 10);
941  0xF7FF, ext_lna << 11);
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);
955  0xFDFF, ext_lna << 9);
957  0xFBFF, ext_lna << 10);
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;
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);
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);
1015 
1016  for (i = 0; i < 500; i++) {
1017  if (!(b43_phy_read(dev,
1019  break;
1020  msleep(1);
1021  }
1022 
1023  if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
1025  return false;
1026  }
1027 
1029  iq_est->iq_prod <<= 16;
1031 
1033  iq_est->i_pwr <<= 16;
1035 
1037  iq_est->q_pwr <<= 16;
1039 
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);
1054  b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
1055  b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
1059  b43_radio_write(dev, B2062_N_TX_CTL_A, 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 
1110  switch (ctl & B43_LPPHY_TX_PWR_CTL_CMD_MODE) {
1113  break;
1116  break;
1119  break;
1120  default:
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:
1136  break;
1137  case B43_LPPHY_TXPCTL_HW:
1139  break;
1140  case B43_LPPHY_TXPCTL_SW:
1142  break;
1143  default:
1144  ctl = 0;
1145  B43_WARN_ON(1);
1146  }
1148  ~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF, ctl);
1149 }
1150 
1151 static void lpphy_set_tx_power_control(struct b43_wldev *dev,
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
1170  0xFF80, lpphy->tssi_idx);
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++) {
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->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);
1299  b43_radio_mask(dev, B2063_PLL_SP1, 0xF7);
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);
1323 
1324  if (crystal_freq == 24000000) {
1327  } else {
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 
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 
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 
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));
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));
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) {
1442  b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
1443  b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0x80FF);
1445  b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0808);
1446  } else {
1448  b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
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);
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);
1531 
1532  if (dev->phy.rev < 2) {
1533  b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF, 0x1000);
1535  } else {
1536  lpphy_set_tx_power_by_index(dev, 0x7F);
1537  }
1538 
1539  b43_dummy_transmission(dev, true, true);
1540 
1542  if (tmp & 0x8000) {
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;
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 
1722  c0 = c1 >> 8;
1723  c1 |= 0xFF;
1724 
1725  b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, 0x00C0);
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 {
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);
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 
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 lpphy_tx_gains gains, oldgains;
1844  int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
1845 
1846  lpphy_read_tx_pctl_mode_from_hardware(dev);
1847  old_txpctl = lpphy->txpctl_mode;
1848  old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
1849  if (old_afe_ovr)
1850  oldgains = lpphy_get_tx_gains(dev);
1851  old_rf = b43_phy_read(dev, B43_LPPHY_RF_PWR_OVERRIDE) & 0xFF;
1852  old_bbmult = lpphy_get_bb_mult(dev);
1853 
1854  lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
1855 
1856  if (dev->dev->chip_id == 0x4325 && dev->dev->chip_rev == 0)
1857  lpphy_papd_cal(dev, gains, 0, 1, 30);
1858  else
1859  lpphy_papd_cal(dev, gains, 0, 1, 65);
1860 
1861  if (old_afe_ovr)
1862  lpphy_set_tx_gains(dev, oldgains);
1863  lpphy_set_bb_mult(dev, old_bbmult);
1864  lpphy_set_tx_power_control(dev, old_txpctl);
1865  b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00, old_rf);
1866 }
1867 
1868 static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
1869  bool rx, bool pa, struct lpphy_tx_gains *gains)
1870 {
1871  struct b43_phy_lp *lpphy = dev->phy.lp;
1872  const struct lpphy_rx_iq_comp *iqcomp = NULL;
1873  struct lpphy_tx_gains nogains, oldgains;
1874  u16 tmp;
1875  int i, ret;
1876 
1877  memset(&nogains, 0, sizeof(nogains));
1878  memset(&oldgains, 0, sizeof(oldgains));
1879 
1880  if (dev->dev->chip_id == 0x5354) {
1881  for (i = 0; i < ARRAY_SIZE(lpphy_5354_iq_table); i++) {
1882  if (lpphy_5354_iq_table[i].chan == lpphy->channel) {
1883  iqcomp = &lpphy_5354_iq_table[i];
1884  }
1885  }
1886  } else if (dev->phy.rev >= 2) {
1887  iqcomp = &lpphy_rev2plus_iq_comp;
1888  } else {
1889  for (i = 0; i < ARRAY_SIZE(lpphy_rev0_1_iq_table); i++) {
1890  if (lpphy_rev0_1_iq_table[i].chan == lpphy->channel) {
1891  iqcomp = &lpphy_rev0_1_iq_table[i];
1892  }
1893  }
1894  }
1895 
1896  if (B43_WARN_ON(!iqcomp))
1897  return 0;
1898 
1899  b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, iqcomp->c1);
1901  0x00FF, iqcomp->c0 << 8);
1902 
1903  if (noise) {
1904  tx = true;
1905  rx = false;
1906  pa = false;
1907  }
1908 
1909  lpphy_set_trsw_over(dev, tx, rx);
1910 
1911  if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
1914  0xFFF7, pa << 3);
1915  } else {
1918  0xFFDF, pa << 5);
1919  }
1920 
1921  tmp = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
1922 
1923  if (noise)
1924  lpphy_set_rx_gain(dev, 0x2D5D);
1925  else {
1926  if (tmp)
1927  oldgains = lpphy_get_tx_gains(dev);
1928  if (!gains)
1929  gains = &nogains;
1930  lpphy_set_tx_gains(dev, *gains);
1931  }
1932 
1933  b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
1934  b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
1935  b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
1937  lpphy_set_deaf(dev, false);
1938  if (noise)
1939  ret = lpphy_calc_rx_iq_comp(dev, 0xFFF0);
1940  else {
1941  lpphy_start_tx_tone(dev, 4000, 100);
1942  ret = lpphy_calc_rx_iq_comp(dev, 0x4000);
1943  lpphy_stop_tx_tone(dev);
1944  }
1945  lpphy_clear_deaf(dev, false);
1946  b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFC);
1947  b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7);
1948  b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFDF);
1949  if (!noise) {
1950  if (tmp)
1951  lpphy_set_tx_gains(dev, oldgains);
1952  else
1953  lpphy_disable_tx_gain_override(dev);
1954  }
1955  lpphy_disable_rx_gain_override(dev);
1956  b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
1957  b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xF7FF);
1958  return ret;
1959 }
1960 
1961 static void lpphy_calibration(struct b43_wldev *dev)
1962 {
1963  struct b43_phy_lp *lpphy = dev->phy.lp;
1964  enum b43_lpphy_txpctl_mode saved_pctl_mode;
1965  bool full_cal = false;
1966 
1967  if (lpphy->full_calib_chan != lpphy->channel) {
1968  full_cal = true;
1969  lpphy->full_calib_chan = lpphy->channel;
1970  }
1971 
1972  b43_mac_suspend(dev);
1973 
1974  lpphy_btcoex_override(dev);
1975  if (dev->phy.rev >= 2)
1976  lpphy_save_dig_flt_state(dev);
1977  lpphy_read_tx_pctl_mode_from_hardware(dev);
1978  saved_pctl_mode = lpphy->txpctl_mode;
1979  lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
1980  //TODO Perform transmit power table I/Q LO calibration
1981  if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF))
1982  lpphy_pr41573_workaround(dev);
1983  if ((dev->phy.rev >= 2) && full_cal) {
1984  lpphy_papd_cal_txpwr(dev);
1985  }
1986  lpphy_set_tx_power_control(dev, saved_pctl_mode);
1987  if (dev->phy.rev >= 2)
1988  lpphy_restore_dig_flt_state(dev);
1989  lpphy_rx_iq_cal(dev, true, true, false, false, NULL);
1990 
1991  b43_mac_enable(dev);
1992 }
1993 
1994 static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg)
1995 {
1996  b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
1997  return b43_read16(dev, B43_MMIO_PHY_DATA);
1998 }
1999 
2000 static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
2001 {
2002  b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
2003  b43_write16(dev, B43_MMIO_PHY_DATA, value);
2004 }
2005 
2006 static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
2007  u16 set)
2008 {
2009  b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
2010  b43_write16(dev, B43_MMIO_PHY_DATA,
2011  (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
2012 }
2013 
2014 static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
2015 {
2016  /* Register 1 is a 32-bit register. */
2017  B43_WARN_ON(reg == 1);
2018  /* LP-PHY needs a special bit set for read access */
2019  if (dev->phy.rev < 2) {
2020  if (reg != 0x4001)
2021  reg |= 0x100;
2022  } else
2023  reg |= 0x200;
2024 
2025  b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
2026  return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
2027 }
2028 
2029 static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
2030 {
2031  /* Register 1 is a 32-bit register. */
2032  B43_WARN_ON(reg == 1);
2033 
2034  b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
2035  b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
2036 }
2037 
2041  u8 data[12];
2042 };
2043 
2044 static const struct b206x_channel b2062_chantbl[] = {
2045  { .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF,
2046  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2047  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2048  { .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF,
2049  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2050  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2051  { .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF,
2052  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2053  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2054  { .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF,
2055  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2056  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2057  { .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF,
2058  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2059  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2060  { .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF,
2061  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2062  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2063  { .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF,
2064  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2065  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2066  { .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF,
2067  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2068  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2069  { .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF,
2070  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2071  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2072  { .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF,
2073  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2074  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2075  { .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF,
2076  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2077  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2078  { .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF,
2079  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2080  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2081  { .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF,
2082  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2083  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2084  { .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF,
2085  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
2086  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
2087  { .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22,
2088  .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
2089  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2090  { .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11,
2091  .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2092  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2093  { .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11,
2094  .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2095  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2096  { .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00,
2097  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2098  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2099  { .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11,
2100  .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2101  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2102  { .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11,
2103  .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
2104  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2105  { .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11,
2106  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2107  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2108  { .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00,
2109  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2110  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2111  { .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00,
2112  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2113  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2114  { .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00,
2115  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
2116  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2117  { .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00,
2118  .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77,
2119  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2120  { .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00,
2121  .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77,
2122  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2123  { .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00,
2124  .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77,
2125  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2126  { .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00,
2127  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
2128  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2129  { .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00,
2130  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
2131  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2132  { .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00,
2133  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
2134  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2135  { .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00,
2136  .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77,
2137  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2138  { .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00,
2139  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2140  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2141  { .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00,
2142  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2143  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2144  { .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00,
2145  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2146  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2147  { .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00,
2148  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2149  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2150  { .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00,
2151  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2152  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2153  { .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00,
2154  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2155  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2156  { .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00,
2157  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2158  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2159  { .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00,
2160  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2161  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2162  { .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00,
2163  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2164  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2165  { .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00,
2166  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2167  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2168  { .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00,
2169  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
2170  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
2171  { .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77,
2172  .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77,
2173  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2174  { .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77,
2175  .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
2176  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2177  { .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66,
2178  .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
2179  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2180  { .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66,
2181  .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
2182  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2183  { .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55,
2184  .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77,
2185  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2186  { .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55,
2187  .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
2188  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2189  { .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44,
2190  .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
2191  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
2192  { .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44,
2193  .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77,
2194  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2195  { .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44,
2196  .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77,
2197  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
2198 };
2199 
2200 static const struct b206x_channel b2063_chantbl[] = {
2201  { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C,
2202  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2203  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2204  .data[10] = 0x80, .data[11] = 0x70, },
2205  { .channel = 2, .freq = 2417, .data[0] = 0x6F, .data[1] = 0x3C,
2206  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2207  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2208  .data[10] = 0x80, .data[11] = 0x70, },
2209  { .channel = 3, .freq = 2422, .data[0] = 0x6F, .data[1] = 0x3C,
2210  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2211  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2212  .data[10] = 0x80, .data[11] = 0x70, },
2213  { .channel = 4, .freq = 2427, .data[0] = 0x6F, .data[1] = 0x2C,
2214  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2215  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2216  .data[10] = 0x80, .data[11] = 0x70, },
2217  { .channel = 5, .freq = 2432, .data[0] = 0x6F, .data[1] = 0x2C,
2218  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2219  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2220  .data[10] = 0x80, .data[11] = 0x70, },
2221  { .channel = 6, .freq = 2437, .data[0] = 0x6F, .data[1] = 0x2C,
2222  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2223  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2224  .data[10] = 0x80, .data[11] = 0x70, },
2225  { .channel = 7, .freq = 2442, .data[0] = 0x6F, .data[1] = 0x2C,
2226  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2227  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2228  .data[10] = 0x80, .data[11] = 0x70, },
2229  { .channel = 8, .freq = 2447, .data[0] = 0x6F, .data[1] = 0x2C,
2230  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2231  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2232  .data[10] = 0x80, .data[11] = 0x70, },
2233  { .channel = 9, .freq = 2452, .data[0] = 0x6F, .data[1] = 0x1C,
2234  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2235  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2236  .data[10] = 0x80, .data[11] = 0x70, },
2237  { .channel = 10, .freq = 2457, .data[0] = 0x6F, .data[1] = 0x1C,
2238  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2239  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2240  .data[10] = 0x80, .data[11] = 0x70, },
2241  { .channel = 11, .freq = 2462, .data[0] = 0x6E, .data[1] = 0x1C,
2242  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2243  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2244  .data[10] = 0x80, .data[11] = 0x70, },
2245  { .channel = 12, .freq = 2467, .data[0] = 0x6E, .data[1] = 0x1C,
2246  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2247  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2248  .data[10] = 0x80, .data[11] = 0x70, },
2249  { .channel = 13, .freq = 2472, .data[0] = 0x6E, .data[1] = 0x1C,
2250  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2251  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2252  .data[10] = 0x80, .data[11] = 0x70, },
2253  { .channel = 14, .freq = 2484, .data[0] = 0x6E, .data[1] = 0x0C,
2254  .data[2] = 0x0C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
2255  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
2256  .data[10] = 0x80, .data[11] = 0x70, },
2257  { .channel = 34, .freq = 5170, .data[0] = 0x6A, .data[1] = 0x0C,
2258  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x02, .data[5] = 0x05,
2259  .data[6] = 0x0D, .data[7] = 0x0D, .data[8] = 0x77, .data[9] = 0x80,
2260  .data[10] = 0x20, .data[11] = 0x00, },
2261  { .channel = 36, .freq = 5180, .data[0] = 0x6A, .data[1] = 0x0C,
2262  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x05,
2263  .data[6] = 0x0D, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
2264  .data[10] = 0x20, .data[11] = 0x00, },
2265  { .channel = 38, .freq = 5190, .data[0] = 0x6A, .data[1] = 0x0C,
2266  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
2267  .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
2268  .data[10] = 0x20, .data[11] = 0x00, },
2269  { .channel = 40, .freq = 5200, .data[0] = 0x69, .data[1] = 0x0C,
2270  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
2271  .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
2272  .data[10] = 0x20, .data[11] = 0x00, },
2273  { .channel = 42, .freq = 5210, .data[0] = 0x69, .data[1] = 0x0C,
2274  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
2275  .data[6] = 0x0B, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
2276  .data[10] = 0x20, .data[11] = 0x00, },
2277  { .channel = 44, .freq = 5220, .data[0] = 0x69, .data[1] = 0x0C,
2278  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x04,
2279  .data[6] = 0x0B, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
2280  .data[10] = 0x20, .data[11] = 0x00, },
2281  { .channel = 46, .freq = 5230, .data[0] = 0x69, .data[1] = 0x0C,
2282  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
2283  .data[6] = 0x0A, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
2284  .data[10] = 0x20, .data[11] = 0x00, },
2285  { .channel = 48, .freq = 5240, .data[0] = 0x69, .data[1] = 0x0C,
2286  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
2287  .data[6] = 0x0A, .data[7] = 0x0A, .data[8] = 0x77, .data[9] = 0x60,
2288  .data[10] = 0x20, .data[11] = 0x00, },
2289  { .channel = 52, .freq = 5260, .data[0] = 0x68, .data[1] = 0x0C,
2290  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x02,
2291  .data[6] = 0x09, .data[7] = 0x09, .data[8] = 0x77, .data[9] = 0x60,
2292  .data[10] = 0x20, .data[11] = 0x00, },
2293  { .channel = 56, .freq = 5280, .data[0] = 0x68, .data[1] = 0x0C,
2294  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
2295  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
2296  .data[10] = 0x10, .data[11] = 0x00, },
2297  { .channel = 60, .freq = 5300, .data[0] = 0x68, .data[1] = 0x0C,
2298  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
2299  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
2300  .data[10] = 0x10, .data[11] = 0x00, },
2301  { .channel = 64, .freq = 5320, .data[0] = 0x67, .data[1] = 0x0C,
2302  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2303  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
2304  .data[10] = 0x10, .data[11] = 0x00, },
2305  { .channel = 100, .freq = 5500, .data[0] = 0x64, .data[1] = 0x0C,
2306  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2307  .data[6] = 0x02, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
2308  .data[10] = 0x00, .data[11] = 0x00, },
2309  { .channel = 104, .freq = 5520, .data[0] = 0x64, .data[1] = 0x0C,
2310  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2311  .data[6] = 0x01, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
2312  .data[10] = 0x00, .data[11] = 0x00, },
2313  { .channel = 108, .freq = 5540, .data[0] = 0x63, .data[1] = 0x0C,
2314  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2315  .data[6] = 0x01, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
2316  .data[10] = 0x00, .data[11] = 0x00, },
2317  { .channel = 112, .freq = 5560, .data[0] = 0x63, .data[1] = 0x0C,
2318  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2319  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
2320  .data[10] = 0x00, .data[11] = 0x00, },
2321  { .channel = 116, .freq = 5580, .data[0] = 0x62, .data[1] = 0x0C,
2322  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2323  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
2324  .data[10] = 0x00, .data[11] = 0x00, },
2325  { .channel = 120, .freq = 5600, .data[0] = 0x62, .data[1] = 0x0C,
2326  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2327  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2328  .data[10] = 0x00, .data[11] = 0x00, },
2329  { .channel = 124, .freq = 5620, .data[0] = 0x62, .data[1] = 0x0C,
2330  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2331  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2332  .data[10] = 0x00, .data[11] = 0x00, },
2333  { .channel = 128, .freq = 5640, .data[0] = 0x61, .data[1] = 0x0C,
2334  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2335  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2336  .data[10] = 0x00, .data[11] = 0x00, },
2337  { .channel = 132, .freq = 5660, .data[0] = 0x61, .data[1] = 0x0C,
2338  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2339  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2340  .data[10] = 0x00, .data[11] = 0x00, },
2341  { .channel = 136, .freq = 5680, .data[0] = 0x61, .data[1] = 0x0C,
2342  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2343  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2344  .data[10] = 0x00, .data[11] = 0x00, },
2345  { .channel = 140, .freq = 5700, .data[0] = 0x60, .data[1] = 0x0C,
2346  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2347  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2348  .data[10] = 0x00, .data[11] = 0x00, },
2349  { .channel = 149, .freq = 5745, .data[0] = 0x60, .data[1] = 0x0C,
2350  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2351  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2352  .data[10] = 0x00, .data[11] = 0x00, },
2353  { .channel = 153, .freq = 5765, .data[0] = 0x60, .data[1] = 0x0C,
2354  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2355  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2356  .data[10] = 0x00, .data[11] = 0x00, },
2357  { .channel = 157, .freq = 5785, .data[0] = 0x60, .data[1] = 0x0C,
2358  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2359  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2360  .data[10] = 0x00, .data[11] = 0x00, },
2361  { .channel = 161, .freq = 5805, .data[0] = 0x60, .data[1] = 0x0C,
2362  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2363  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2364  .data[10] = 0x00, .data[11] = 0x00, },
2365  { .channel = 165, .freq = 5825, .data[0] = 0x60, .data[1] = 0x0C,
2366  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
2367  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
2368  .data[10] = 0x00, .data[11] = 0x00, },
2369  { .channel = 184, .freq = 4920, .data[0] = 0x6E, .data[1] = 0x0C,
2370  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0E,
2371  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xC0,
2372  .data[10] = 0x50, .data[11] = 0x00, },
2373  { .channel = 188, .freq = 4940, .data[0] = 0x6E, .data[1] = 0x0C,
2374  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0D,
2375  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
2376  .data[10] = 0x50, .data[11] = 0x00, },
2377  { .channel = 192, .freq = 4960, .data[0] = 0x6E, .data[1] = 0x0C,
2378  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
2379  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
2380  .data[10] = 0x50, .data[11] = 0x00, },
2381  { .channel = 196, .freq = 4980, .data[0] = 0x6D, .data[1] = 0x0C,
2382  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
2383  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
2384  .data[10] = 0x40, .data[11] = 0x00, },
2385  { .channel = 200, .freq = 5000, .data[0] = 0x6D, .data[1] = 0x0C,
2386  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0B,
2387  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
2388  .data[10] = 0x40, .data[11] = 0x00, },
2389  { .channel = 204, .freq = 5020, .data[0] = 0x6D, .data[1] = 0x0C,
2390  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0A,
2391  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
2392  .data[10] = 0x40, .data[11] = 0x00, },
2393  { .channel = 208, .freq = 5040, .data[0] = 0x6C, .data[1] = 0x0C,
2394  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x07, .data[5] = 0x09,
2395  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
2396  .data[10] = 0x40, .data[11] = 0x00, },
2397  { .channel = 212, .freq = 5060, .data[0] = 0x6C, .data[1] = 0x0C,
2398  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x06, .data[5] = 0x08,
2399  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
2400  .data[10] = 0x40, .data[11] = 0x00, },
2401  { .channel = 216, .freq = 5080, .data[0] = 0x6C, .data[1] = 0x0C,
2402  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x05, .data[5] = 0x08,
2403  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
2404  .data[10] = 0x40, .data[11] = 0x00, },
2405 };
2406 
2407 static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
2408 {
2409  b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
2410  udelay(20);
2411  if (dev->dev->chip_id == 0x5354) {
2412  b43_radio_write(dev, B2062_N_COMM1, 4);
2414  } else {
2416  }
2417  udelay(5);
2418 }
2419 
2420 static void lpphy_b2062_vco_calib(struct b43_wldev *dev)
2421 {
2424  udelay(200);
2425 }
2426 
2427 static int lpphy_b2062_tune(struct b43_wldev *dev,
2428  unsigned int channel)
2429 {
2430  struct b43_phy_lp *lpphy = dev->phy.lp;
2431  struct ssb_bus *bus = dev->dev->sdev->bus;
2432  const struct b206x_channel *chandata = NULL;
2433  u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
2434  u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
2435  int i, err = 0;
2436 
2437  for (i = 0; i < ARRAY_SIZE(b2062_chantbl); i++) {
2438  if (b2062_chantbl[i].channel == channel) {
2439  chandata = &b2062_chantbl[i];
2440  break;
2441  }
2442  }
2443 
2444  if (B43_WARN_ON(!chandata))
2445  return -EINVAL;
2446 
2447  b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04);
2448  b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]);
2449  b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]);
2450  b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]);
2451  b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]);
2452  b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]);
2453  b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]);
2454  b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]);
2455  b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]);
2456  b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]);
2457 
2458  tmp1 = crystal_freq / 1000;
2459  tmp2 = lpphy->pdiv * 1000;
2462  lpphy_b2062_reset_pll_bias(dev);
2463  tmp3 = tmp2 * channel2freq_lp(channel);
2464  if (channel2freq_lp(channel) < 4000)
2465  tmp3 *= 2;
2466  tmp4 = 48 * tmp1;
2467  tmp6 = tmp3 / tmp4;
2468  tmp7 = tmp3 % tmp4;
2470  tmp5 = tmp7 * 0x100;
2471  tmp6 = tmp5 / tmp4;
2472  tmp7 = tmp5 % tmp4;
2474  tmp5 = tmp7 * 0x100;
2475  tmp6 = tmp5 / tmp4;
2476  tmp7 = tmp5 % tmp4;
2478  tmp5 = tmp7 * 0x100;
2479  tmp6 = tmp5 / tmp4;
2480  tmp7 = tmp5 % tmp4;
2481  b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4));
2482  tmp8 = b43_radio_read(dev, B2062_S_RFPLL_CTL19);
2483  tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1);
2484  b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16);
2485  b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF);
2486 
2487  lpphy_b2062_vco_calib(dev);
2488  if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) {
2491  lpphy_b2062_reset_pll_bias(dev);
2492  lpphy_b2062_vco_calib(dev);
2493  if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10)
2494  err = -EIO;
2495  }
2496 
2497  b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04);
2498  return err;
2499 }
2500 
2501 static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
2502 {
2503  u16 tmp;
2504 
2505  b43_radio_mask(dev, B2063_PLL_SP1, ~0x40);
2506  tmp = b43_radio_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8;
2508  udelay(1);
2509  b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4);
2510  udelay(1);
2511  b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6);
2512  udelay(1);
2513  b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7);
2514  udelay(300);
2515  b43_radio_set(dev, B2063_PLL_SP1, 0x40);
2516 }
2517 
2518 static int lpphy_b2063_tune(struct b43_wldev *dev,
2519  unsigned int channel)
2520 {
2521  struct ssb_bus *bus = dev->dev->sdev->bus;
2522 
2523  static const struct b206x_channel *chandata = NULL;
2524  u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
2525  u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count;
2526  u16 old_comm15, scale;
2527  u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
2528  int i, div = (crystal_freq <= 26000000 ? 1 : 2);
2529 
2530  for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) {
2531  if (b2063_chantbl[i].channel == channel) {
2532  chandata = &b2063_chantbl[i];
2533  break;
2534  }
2535  }
2536 
2537  if (B43_WARN_ON(!chandata))
2538  return -EINVAL;
2539 
2540  b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]);
2541  b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]);
2542  b43_radio_write(dev, B2063_LOGEN_BUF2, chandata->data[2]);
2543  b43_radio_write(dev, B2063_LOGEN_RCCR1, chandata->data[3]);
2544  b43_radio_write(dev, B2063_A_RX_1ST3, chandata->data[4]);
2545  b43_radio_write(dev, B2063_A_RX_2ND1, chandata->data[5]);
2546  b43_radio_write(dev, B2063_A_RX_2ND4, chandata->data[6]);
2547  b43_radio_write(dev, B2063_A_RX_2ND7, chandata->data[7]);
2548  b43_radio_write(dev, B2063_A_RX_PS6, chandata->data[8]);
2549  b43_radio_write(dev, B2063_TX_RF_CTL2, chandata->data[9]);
2550  b43_radio_write(dev, B2063_TX_RF_CTL5, chandata->data[10]);
2551  b43_radio_write(dev, B2063_PA_CTL11, chandata->data[11]);
2552 
2553  old_comm15 = b43_radio_read(dev, B2063_COMM15);
2554  b43_radio_set(dev, B2063_COMM15, 0x1E);
2555 
2556  if (chandata->freq > 4000) /* spec says 2484, but 4000 is safer */
2557  vco_freq = chandata->freq << 1;
2558  else
2559  vco_freq = chandata->freq << 2;
2560 
2561  freqref = crystal_freq * 3;
2562  val1 = lpphy_qdiv_roundup(crystal_freq, 1000000, 16);
2563  val2 = lpphy_qdiv_roundup(crystal_freq, 1000000 * div, 16);
2564  val3 = lpphy_qdiv_roundup(vco_freq, 3, 16);
2565  timeout = ((((8 * crystal_freq) / (div * 5000000)) + 1) >> 1) - 1;
2568  0xFFF8, timeout >> 2);
2570  0xFF9F,timeout << 5);
2571 
2572  timeoutref = ((((8 * crystal_freq) / (div * (timeout + 1))) +
2573  999999) / 1000000) + 1;
2575 
2576  count = lpphy_qdiv_roundup(val3, val2 + 16, 16);
2577  count *= (timeout + 1) * (timeoutref + 1);
2578  count--;
2580  0xF0, count >> 8);
2581  b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB8, count & 0xFF);
2582 
2583  tmp1 = ((val3 * 62500) / freqref) << 4;
2584  tmp2 = ((val3 * 62500) % freqref) << 4;
2585  while (tmp2 >= freqref) {
2586  tmp1++;
2587  tmp2 -= freqref;
2588  }
2589  b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG1, 0xFFE0, tmp1 >> 4);
2590  b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFE0F, tmp1 << 4);
2591  b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFFF0, tmp1 >> 16);
2592  b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG3, (tmp2 >> 8) & 0xFF);
2593  b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG4, tmp2 & 0xFF);
2594 
2599 
2600  tmp3 = ((41 * (val3 - 3000)) /1200) + 27;
2601  tmp4 = lpphy_qdiv_roundup(132000 * tmp1, 8451, 16);
2602 
2603  if ((tmp4 + tmp3 - 1) / tmp3 > 60) {
2604  scale = 1;
2605  tmp5 = ((tmp4 + tmp3) / (tmp3 << 1)) - 8;
2606  } else {
2607  scale = 0;
2608  tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8;
2609  }
2610  b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5);
2611  b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6);
2612 
2613  tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16);
2614  tmp6 *= (tmp5 * 8) * (scale + 1);
2615  if (tmp6 > 150)
2616  tmp6 = 0;
2617 
2618  b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6);
2619  b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5);
2620 
2621  b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4);
2622  if (crystal_freq > 26000000)
2624  else
2626 
2627  if (val1 == 45)
2629  else
2631 
2632  b43_radio_set(dev, B2063_PLL_SP2, 0x3);
2633  udelay(1);
2634  b43_radio_mask(dev, B2063_PLL_SP2, 0xFFFC);
2635  lpphy_b2063_vco_calib(dev);
2636  b43_radio_write(dev, B2063_COMM15, old_comm15);
2637 
2638  return 0;
2639 }
2640 
2641 static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
2642  unsigned int new_channel)
2643 {
2644  struct b43_phy_lp *lpphy = dev->phy.lp;
2645  int err;
2646 
2647  if (dev->phy.radio_ver == 0x2063) {
2648  err = lpphy_b2063_tune(dev, new_channel);
2649  if (err)
2650  return err;
2651  } else {
2652  err = lpphy_b2062_tune(dev, new_channel);
2653  if (err)
2654  return err;
2655  lpphy_set_analog_filter(dev, new_channel);
2656  lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel));
2657  }
2658 
2659  lpphy->channel = new_channel;
2660  b43_write16(dev, B43_MMIO_CHANNEL, new_channel);
2661 
2662  return 0;
2663 }
2664 
2665 static int b43_lpphy_op_init(struct b43_wldev *dev)
2666 {
2667  int err;
2668 
2669  if (dev->dev->bus_type != B43_BUS_SSB) {
2670  b43err(dev->wl, "LP-PHY is supported only on SSB!\n");
2671  return -EOPNOTSUPP;
2672  }
2673 
2674  lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs?
2675  lpphy_baseband_init(dev);
2676  lpphy_radio_init(dev);
2677  lpphy_calibrate_rc(dev);
2678  err = b43_lpphy_op_switch_channel(dev, 7);
2679  if (err) {
2680  b43dbg(dev->wl, "Switch to channel 7 failed, error = %d.\n",
2681  err);
2682  }
2683  lpphy_tx_pctl_init(dev);
2684  lpphy_calibration(dev);
2685  //TODO ACI init
2686 
2687  return 0;
2688 }
2689 
2690 static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
2691 {
2692  //TODO
2693 }
2694 
2695 static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
2696  bool ignore_tssi)
2697 {
2698  //TODO
2699  return B43_TXPWR_RES_DONE;
2700 }
2701 
2702 static void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
2703 {
2704  if (on) {
2705  b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xfff8);
2706  } else {
2707  b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0x0007);
2708  b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x0007);
2709  }
2710 }
2711 
2712 static void b43_lpphy_op_pwork_15sec(struct b43_wldev *dev)
2713 {
2714  //TODO
2715 }
2716 
2718  .allocate = b43_lpphy_op_allocate,
2719  .free = b43_lpphy_op_free,
2720  .prepare_structs = b43_lpphy_op_prepare_structs,
2721  .init = b43_lpphy_op_init,
2722  .phy_read = b43_lpphy_op_read,
2723  .phy_write = b43_lpphy_op_write,
2724  .phy_maskset = b43_lpphy_op_maskset,
2725  .radio_read = b43_lpphy_op_radio_read,
2726  .radio_write = b43_lpphy_op_radio_write,
2727  .software_rfkill = b43_lpphy_op_software_rfkill,
2728  .switch_analog = b43_lpphy_op_switch_analog,
2729  .switch_channel = b43_lpphy_op_switch_channel,
2730  .get_default_chan = b43_lpphy_op_get_default_chan,
2731  .set_rx_antenna = b43_lpphy_op_set_rx_antenna,
2732  .recalc_txpower = b43_lpphy_op_recalc_txpower,
2733  .adjust_txpower = b43_lpphy_op_adjust_txpower,
2734  .pwork_15sec = b43_lpphy_op_pwork_15sec,
2735  .pwork_60sec = lpphy_calibration,
2736 };