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