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