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