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