aa1a298131b4d5482d36b1db7f50c81e09231b66
[openwrt/staging/yousong.git] / package / bcm43xx-mac80211 / src / bcm43xx / bcm43xx_lo.c
1 /*
2
3 Broadcom BCM43xx wireless driver
4
5 G PHY LO (LocalOscillator) Measuring and Control routines
6
7 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
8 Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
9 Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
10 Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
11 Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; see the file COPYING. If not, write to
25 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
26 Boston, MA 02110-1301, USA.
27
28 */
29
30 #include "bcm43xx.h"
31 #include "bcm43xx_lo.h"
32 #include "bcm43xx_phy.h"
33 #include "bcm43xx_main.h"
34
35 #include <linux/delay.h>
36 #include <linux/sched.h>
37
38
39 /* Write the LocalOscillator Control (adjust) value-pair. */
40 static void bcm43xx_lo_write(struct bcm43xx_wldev *dev,
41 struct bcm43xx_loctl *control)
42 {
43 struct bcm43xx_phy *phy = &dev->phy;
44 u16 value;
45 u16 reg;
46
47 if (BCM43xx_DEBUG) {
48 if (unlikely(abs(control->i) > 16 ||
49 abs(control->q) > 16)) {
50 printk(KERN_ERR PFX "ERROR: Invalid LO control pair "
51 "(I: %d, Q: %d)\n",
52 control->i, control->q);
53 dump_stack();
54 return;
55 }
56 }
57
58 value = (u8)(control->q);
59 value |= ((u8)(control->i)) << 8;
60
61 reg = (phy->type == BCM43xx_PHYTYPE_B) ? 0x002F : BCM43xx_PHY_LO_CTL;
62 bcm43xx_phy_write(dev, reg, value);
63 }
64
65 static inline
66 int assert_rfatt_and_bbatt(const struct bcm43xx_rfatt *rfatt,
67 const struct bcm43xx_bbatt *bbatt)
68 {
69 int err = 0;
70
71 /* Check the attenuation values against the LO control array sizes. */
72 #if BCM43xx_DEBUG
73 if (rfatt->att >= BCM43xx_NR_RF) {
74 dprintk(KERN_ERR PFX
75 "ERROR: rfatt(%u) >= size of LO array\n",
76 rfatt->att);
77 err = -EINVAL;
78 }
79 if (bbatt->att >= BCM43xx_NR_BB) {
80 dprintk(KERN_ERR PFX
81 "ERROR: bbatt(%u) >= size of LO array\n",
82 bbatt->att);
83 err = -EINVAL;
84 }
85 if (err)
86 dump_stack();
87 #endif /* BCM43xx_DEBUG */
88
89 return err;
90 }
91
92 static
93 struct bcm43xx_loctl * bcm43xx_get_lo_g_ctl_nopadmix(struct bcm43xx_wldev *dev,
94 const struct bcm43xx_rfatt *rfatt,
95 const struct bcm43xx_bbatt *bbatt)
96 {
97 struct bcm43xx_phy *phy = &dev->phy;
98 struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
99
100 if (assert_rfatt_and_bbatt(rfatt, bbatt))
101 return &(lo->no_padmix[0][0]); /* Just prevent a crash */
102 return &(lo->no_padmix[bbatt->att][rfatt->att]);
103 }
104
105 struct bcm43xx_loctl * bcm43xx_get_lo_g_ctl(struct bcm43xx_wldev *dev,
106 const struct bcm43xx_rfatt *rfatt,
107 const struct bcm43xx_bbatt *bbatt)
108 {
109 struct bcm43xx_phy *phy = &dev->phy;
110 struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
111
112 if (assert_rfatt_and_bbatt(rfatt, bbatt))
113 return &(lo->no_padmix[0][0]); /* Just prevent a crash */
114 if (rfatt->with_padmix)
115 return &(lo->with_padmix[bbatt->att][rfatt->att]);
116 return &(lo->no_padmix[bbatt->att][rfatt->att]);
117 }
118
119 /* Call a function for every possible LO control value-pair. */
120 static void bcm43xx_call_for_each_loctl(struct bcm43xx_wldev *dev,
121 void (*func)(struct bcm43xx_wldev *,
122 struct bcm43xx_loctl *))
123 {
124 struct bcm43xx_phy *phy = &dev->phy;
125 struct bcm43xx_txpower_lo_control *ctl = phy->lo_control;
126 int i, j;
127
128 for (i = 0; i < BCM43xx_NR_BB; i++) {
129 for (j = 0; j < BCM43xx_NR_RF; j++)
130 func(dev, &(ctl->with_padmix[i][j]));
131 }
132 for (i = 0; i < BCM43xx_NR_BB; i++) {
133 for (j = 0; j < BCM43xx_NR_RF; j++)
134 func(dev, &(ctl->no_padmix[i][j]));
135 }
136 }
137
138 static u16 lo_b_r15_loop(struct bcm43xx_wldev *dev)
139 {
140 int i;
141 u16 ret = 0;
142
143 for (i = 0; i < 10; i++){
144 bcm43xx_phy_write(dev, 0x0015, 0xAFA0);
145 udelay(1);
146 bcm43xx_phy_write(dev, 0x0015, 0xEFA0);
147 udelay(10);
148 bcm43xx_phy_write(dev, 0x0015, 0xFFA0);
149 udelay(40);
150 ret += bcm43xx_phy_read(dev, 0x002C);
151 }
152
153 return ret;
154 }
155
156 void bcm43xx_lo_b_measure(struct bcm43xx_wldev *dev)
157 {
158 struct bcm43xx_phy *phy = &dev->phy;
159 u16 regstack[12] = { 0 };
160 u16 mls;
161 u16 fval;
162 int i, j;
163
164 regstack[0] = bcm43xx_phy_read(dev, 0x0015);
165 regstack[1] = bcm43xx_radio_read16(dev, 0x0052) & 0xFFF0;
166
167 if (phy->radio_ver == 0x2053) {
168 regstack[2] = bcm43xx_phy_read(dev, 0x000A);
169 regstack[3] = bcm43xx_phy_read(dev, 0x002A);
170 regstack[4] = bcm43xx_phy_read(dev, 0x0035);
171 regstack[5] = bcm43xx_phy_read(dev, 0x0003);
172 regstack[6] = bcm43xx_phy_read(dev, 0x0001);
173 regstack[7] = bcm43xx_phy_read(dev, 0x0030);
174
175 regstack[8] = bcm43xx_radio_read16(dev, 0x0043);
176 regstack[9] = bcm43xx_radio_read16(dev, 0x007A);
177 regstack[10] = bcm43xx_read16(dev, 0x03EC);
178 regstack[11] = bcm43xx_radio_read16(dev, 0x0052) & 0x00F0;
179
180 bcm43xx_phy_write(dev, 0x0030, 0x00FF);
181 bcm43xx_write16(dev, 0x03EC, 0x3F3F);
182 bcm43xx_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
183 bcm43xx_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
184 }
185 bcm43xx_phy_write(dev, 0x0015, 0xB000);
186 bcm43xx_phy_write(dev, 0x002B, 0x0004);
187
188 if (phy->radio_ver == 0x2053) {
189 bcm43xx_phy_write(dev, 0x002B, 0x0203);
190 bcm43xx_phy_write(dev, 0x002A, 0x08A3);
191 }
192
193 phy->minlowsig[0] = 0xFFFF;
194
195 for (i = 0; i < 4; i++) {
196 bcm43xx_radio_write16(dev, 0x0052, regstack[1] | i);
197 lo_b_r15_loop(dev);
198 }
199 for (i = 0; i < 10; i++) {
200 bcm43xx_radio_write16(dev, 0x0052, regstack[1] | i);
201 mls = lo_b_r15_loop(dev) / 10;
202 if (mls < phy->minlowsig[0]) {
203 phy->minlowsig[0] = mls;
204 phy->minlowsigpos[0] = i;
205 }
206 }
207 bcm43xx_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]);
208
209 phy->minlowsig[1] = 0xFFFF;
210
211 for (i = -4; i < 5; i += 2) {
212 for (j = -4; j < 5; j += 2) {
213 if (j < 0)
214 fval = (0x0100 * i) + j + 0x0100;
215 else
216 fval = (0x0100 * i) + j;
217 bcm43xx_phy_write(dev, 0x002F, fval);
218 mls = lo_b_r15_loop(dev) / 10;
219 if (mls < phy->minlowsig[1]) {
220 phy->minlowsig[1] = mls;
221 phy->minlowsigpos[1] = fval;
222 }
223 }
224 }
225 phy->minlowsigpos[1] += 0x0101;
226
227 bcm43xx_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
228 if (phy->radio_ver == 0x2053) {
229 bcm43xx_phy_write(dev, 0x000A, regstack[2]);
230 bcm43xx_phy_write(dev, 0x002A, regstack[3]);
231 bcm43xx_phy_write(dev, 0x0035, regstack[4]);
232 bcm43xx_phy_write(dev, 0x0003, regstack[5]);
233 bcm43xx_phy_write(dev, 0x0001, regstack[6]);
234 bcm43xx_phy_write(dev, 0x0030, regstack[7]);
235
236 bcm43xx_radio_write16(dev, 0x0043, regstack[8]);
237 bcm43xx_radio_write16(dev, 0x007A, regstack[9]);
238
239 bcm43xx_radio_write16(dev, 0x0052,
240 (bcm43xx_radio_read16(dev, 0x0052) & 0x000F)
241 | regstack[11]);
242
243 bcm43xx_write16(dev, 0x03EC, regstack[10]);
244 }
245 bcm43xx_phy_write(dev, 0x0015, regstack[0]);
246 }
247
248 static u16 lo_measure_feedthrough(struct bcm43xx_wldev *dev,
249 u16 lna, u16 pga, u16 trsw_rx)
250 {
251 struct bcm43xx_phy *phy = &dev->phy;
252 u16 rfover;
253 u16 feedthrough;
254
255 if (phy->gmode) {
256 lna <<= BCM43xx_PHY_RFOVERVAL_LNA_SHIFT;
257 pga <<= BCM43xx_PHY_RFOVERVAL_PGA_SHIFT;
258
259 assert((lna & ~BCM43xx_PHY_RFOVERVAL_LNA) == 0);
260 assert((pga & ~BCM43xx_PHY_RFOVERVAL_PGA) == 0);
261 /*FIXME This assertion fails assert((trsw_rx & ~(BCM43xx_PHY_RFOVERVAL_TRSWRX |
262 BCM43xx_PHY_RFOVERVAL_BW)) == 0);
263 */
264 trsw_rx &= (BCM43xx_PHY_RFOVERVAL_TRSWRX | BCM43xx_PHY_RFOVERVAL_BW);
265
266 /* Construct the RF Override Value */
267 rfover = BCM43xx_PHY_RFOVERVAL_UNK;
268 rfover |= pga;
269 rfover |= lna;
270 rfover |= trsw_rx;
271 if ((dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_EXTLNA) &&
272 phy->rev > 6)
273 rfover |= BCM43xx_PHY_RFOVERVAL_EXTLNA;
274
275 bcm43xx_phy_write(dev, BCM43xx_PHY_PGACTL, 0xE300);
276 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVERVAL, rfover);
277 udelay(10);
278 rfover |= BCM43xx_PHY_RFOVERVAL_BW_LBW;
279 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVERVAL, rfover);
280 udelay(10);
281 rfover |= BCM43xx_PHY_RFOVERVAL_BW_LPF;
282 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVERVAL, rfover);
283 udelay(10);
284 bcm43xx_phy_write(dev, BCM43xx_PHY_PGACTL, 0xF300);
285 } else {
286 pga |= BCM43xx_PHY_PGACTL_UNKNOWN;
287 bcm43xx_phy_write(dev, BCM43xx_PHY_PGACTL, pga);
288 udelay(10);
289 pga |= BCM43xx_PHY_PGACTL_LOWBANDW;
290 bcm43xx_phy_write(dev, BCM43xx_PHY_PGACTL, pga);
291 udelay(10);
292 pga |= BCM43xx_PHY_PGACTL_LPF;
293 bcm43xx_phy_write(dev, BCM43xx_PHY_PGACTL, pga);
294 }
295 udelay(21);
296 feedthrough = bcm43xx_phy_read(dev, BCM43xx_PHY_LO_LEAKAGE);
297
298 /* This is a good place to check if we need to relax a bit,
299 * as this is the main function called regularly
300 * in the LO calibration. */
301 cond_resched();
302
303 return feedthrough;
304 }
305
306 /* TXCTL Register and Value Table.
307 * Returns the "TXCTL Register".
308 * "value" is the "TXCTL Value".
309 * "pad_mix_gain" is the PAD Mixer Gain.
310 */
311 static u16 lo_txctl_register_table(struct bcm43xx_wldev *dev,
312 u16 *value, u16 *pad_mix_gain)
313 {
314 struct bcm43xx_phy *phy = &dev->phy;
315 u16 reg, v, padmix;
316
317 if (phy->type == BCM43xx_PHYTYPE_B) {
318 v = 0x30;
319 if (phy->radio_rev <= 5) {
320 reg = 0x43;
321 padmix = 0;
322 } else {
323 reg = 0x52;
324 padmix = 5;
325 }
326 } else {
327 if (phy->rev >= 2 && phy->radio_rev == 8) {
328 reg = 0x43;
329 v = 0x10;
330 padmix = 2;
331 } else {
332 reg = 0x52;
333 v = 0x30;
334 padmix = 5;
335 }
336 }
337 if (value)
338 *value = v;
339 if (pad_mix_gain)
340 *pad_mix_gain = padmix;
341
342 return reg;
343 }
344
345 static void lo_measure_txctl_values(struct bcm43xx_wldev *dev)
346 {
347 struct bcm43xx_phy *phy = &dev->phy;
348 struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
349 u16 reg, mask;
350 u16 trsw_rx, pga;
351 u16 radio_pctl_reg;
352
353 static const u8 tx_bias_values[] = {
354 0x09, 0x08, 0x0A, 0x01, 0x00,
355 0x02, 0x05, 0x04, 0x06,
356 };
357 static const u8 tx_magn_values[] = {
358 0x70, 0x40,
359 };
360
361 if (!has_loopback_gain(phy)) {
362 radio_pctl_reg = 6;
363 trsw_rx = 2;
364 pga = 0;
365 } else {
366 int lb_gain; /* Loopback gain (in dB) */
367
368 trsw_rx = 0;
369 lb_gain = phy->max_lb_gain / 2;
370 if (lb_gain > 10) {
371 radio_pctl_reg = 0;
372 pga = abs(10 - lb_gain) / 6;
373 pga = limit_value(pga, 0, 15);
374 } else {
375 int cmp_val;
376 int tmp;
377
378 pga = 0;
379 cmp_val = 0x24;
380 if ((phy->rev >= 2) &&
381 (phy->radio_ver == 0x2050) &&
382 (phy->radio_rev == 8))
383 cmp_val = 0x3C;
384 tmp = lb_gain;
385 if ((10 - lb_gain) < cmp_val)
386 tmp = (10 - lb_gain);
387 if (tmp < 0)
388 tmp += 6;
389 else
390 tmp += 3;
391 cmp_val /= 4;
392 tmp /= 4;
393 if (tmp >= cmp_val)
394 radio_pctl_reg = cmp_val;
395 else
396 radio_pctl_reg = tmp;
397 }
398 }
399 bcm43xx_radio_write16(dev, 0x43,
400 (bcm43xx_radio_read16(dev, 0x43)
401 & 0xFFF0) | radio_pctl_reg);
402 bcm43xx_phy_set_baseband_attenuation(dev, 2);
403
404 reg = lo_txctl_register_table(dev, &mask, NULL);
405 mask = ~mask;
406 bcm43xx_radio_write16(dev, reg,
407 bcm43xx_radio_read16(dev, reg)
408 & mask);
409
410 if (has_tx_magnification(phy)) {
411 int i, j;
412 int feedthrough;
413 int min_feedth = 0xFFFF;
414 u8 tx_magn, tx_bias;
415
416 for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) {
417 tx_magn = tx_magn_values[i];
418 bcm43xx_radio_write16(dev, 0x52,
419 (bcm43xx_radio_read16(dev, 0x52)
420 & 0xFF0F) | tx_magn);
421 for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) {
422 tx_bias = tx_bias_values[j];
423 bcm43xx_radio_write16(dev, 0x52,
424 (bcm43xx_radio_read16(dev, 0x52)
425 & 0xFFF0) | tx_bias);
426 feedthrough = lo_measure_feedthrough(dev, 0, pga, trsw_rx);
427 if (feedthrough < min_feedth) {
428 lo->tx_bias = tx_bias;
429 lo->tx_magn = tx_magn;
430 min_feedth = feedthrough;
431 }
432 if (lo->tx_bias == 0)
433 break;
434 }
435 bcm43xx_radio_write16(dev, 0x52,
436 (bcm43xx_radio_read16(dev, 0x52)
437 & 0xFF00) | lo->tx_bias | lo->tx_magn);
438 }
439 } else {
440 lo->tx_magn = 0;
441 lo->tx_bias = 0;
442 bcm43xx_radio_write16(dev, 0x52,
443 bcm43xx_radio_read16(dev, 0x52)
444 & 0xFFF0); /* TX bias == 0 */
445 }
446 }
447
448 static void lo_read_power_vector(struct bcm43xx_wldev *dev)
449 {
450 struct bcm43xx_phy *phy = &dev->phy;
451 struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
452 u16 i;
453 u64 tmp;
454 u64 power_vector = 0;
455 int rf_offset, bb_offset;
456 struct bcm43xx_loctl *loctl;
457
458 for (i = 0; i < 8; i += 2) {
459 tmp = bcm43xx_shm_read16(dev, BCM43xx_SHM_SHARED,
460 0x310 + i);
461 /* Clear the top byte. We get holes in the bitmap... */
462 tmp &= 0xFF;
463 power_vector |= (tmp << (i * 8));
464 /* Clear the vector on the device. */
465 bcm43xx_shm_write16(dev, BCM43xx_SHM_SHARED,
466 0x310 + i, 0);
467 }
468
469 if (power_vector)
470 lo->power_vector = power_vector;
471 power_vector = lo->power_vector;
472
473 for (i = 0; i < 64; i++) {
474 if (power_vector & ((u64)1ULL << i)) {
475 /* Now figure out which bcm43xx_loctl corresponds
476 * to this bit.
477 */
478 rf_offset = i / lo->rfatt_list.len;
479 bb_offset = i % lo->rfatt_list.len;//FIXME?
480 loctl = bcm43xx_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset],
481 &lo->bbatt_list.list[bb_offset]);
482 /* And mark it as "used", as the device told us
483 * through the bitmap it is using it.
484 */
485 loctl->used = 1;
486 }
487 }
488 }
489
490 /* 802.11/LO/GPHY/MeasuringGains */
491 static void lo_measure_gain_values(struct bcm43xx_wldev *dev,
492 s16 max_rx_gain,
493 int use_trsw_rx)
494 {
495 struct bcm43xx_phy *phy = &dev->phy;
496 u16 tmp;
497
498 if (max_rx_gain < 0)
499 max_rx_gain = 0;
500
501 if (has_loopback_gain(phy)) {
502 int trsw_rx = 0;
503 int trsw_rx_gain;
504
505 if (use_trsw_rx) {
506 trsw_rx_gain = phy->trsw_rx_gain / 2;
507 if (max_rx_gain >= trsw_rx_gain) {
508 trsw_rx_gain = max_rx_gain - trsw_rx_gain;
509 trsw_rx = 0x20;
510 }
511 } else
512 trsw_rx_gain = max_rx_gain;
513 if (trsw_rx_gain < 9) {
514 phy->lna_lod_gain = 0;
515 } else {
516 phy->lna_lod_gain = 1;
517 trsw_rx_gain -= 8;
518 }
519 trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D);
520 phy->pga_gain = trsw_rx_gain / 3;
521 if (phy->pga_gain >= 5) {
522 phy->pga_gain -= 5;
523 phy->lna_gain = 2;
524 } else
525 phy->lna_gain = 0;
526 } else {
527 phy->lna_gain = 0;
528 phy->trsw_rx_gain = 0x20;
529 if (max_rx_gain >= 0x14) {
530 phy->lna_lod_gain = 1;
531 phy->pga_gain = 2;
532 } else if (max_rx_gain >= 0x12) {
533 phy->lna_lod_gain = 1;
534 phy->pga_gain = 1;
535 } else if (max_rx_gain >= 0xF) {
536 phy->lna_lod_gain = 1;
537 phy->pga_gain = 0;
538 } else {
539 phy->lna_lod_gain = 0;
540 phy->pga_gain = 0;
541 }
542 }
543
544 tmp = bcm43xx_radio_read16(dev, 0x7A);
545 if (phy->lna_lod_gain == 0)
546 tmp &= ~0x0008;
547 else
548 tmp |= 0x0008;
549 bcm43xx_radio_write16(dev, 0x7A, tmp);
550 }
551
552 struct lo_g_saved_values {
553 u8 old_channel;
554
555 /* Core registers */
556 u16 reg_3F4;
557 u16 reg_3E2;
558
559 /* PHY registers */
560 u16 phy_lo_mask;
561 u16 phy_extg_01;
562 u16 phy_dacctl_hwpctl;
563 u16 phy_dacctl;
564 u16 phy_base_14;
565 u16 phy_hpwr_tssictl;
566 u16 phy_analogover;
567 u16 phy_analogoverval;
568 u16 phy_rfover;
569 u16 phy_rfoverval;
570 u16 phy_classctl;
571 u16 phy_base_3E;
572 u16 phy_crs0;
573 u16 phy_pgactl;
574 u16 phy_base_2A;
575 u16 phy_syncctl;
576 u16 phy_base_30;
577 u16 phy_base_06;
578
579 /* Radio registers */
580 u16 radio_43;
581 u16 radio_7A;
582 u16 radio_52;
583 };
584
585 static void lo_measure_setup(struct bcm43xx_wldev *dev,
586 struct lo_g_saved_values *sav)
587 {
588 struct ssb_sprom *sprom = &dev->dev->bus->sprom;
589 struct bcm43xx_phy *phy = &dev->phy;
590 struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
591 u16 tmp;
592
593 if (has_hardware_pctl(phy)) {
594 sav->phy_lo_mask = bcm43xx_phy_read(dev, BCM43xx_PHY_LO_MASK);
595 sav->phy_extg_01 = bcm43xx_phy_read(dev, BCM43xx_PHY_EXTG(0x01));
596 sav->phy_dacctl_hwpctl = bcm43xx_phy_read(dev, BCM43xx_PHY_DACCTL);
597 sav->phy_base_14 = bcm43xx_phy_read(dev, BCM43xx_PHY_BASE(0x14));
598 sav->phy_hpwr_tssictl = bcm43xx_phy_read(dev, BCM43xx_PHY_HPWR_TSSICTL);
599
600 bcm43xx_phy_write(dev, BCM43xx_PHY_HPWR_TSSICTL,
601 bcm43xx_phy_read(dev, BCM43xx_PHY_HPWR_TSSICTL)
602 | 0x100);
603 bcm43xx_phy_write(dev, BCM43xx_PHY_EXTG(0x01),
604 bcm43xx_phy_read(dev, BCM43xx_PHY_EXTG(0x01))
605 | 0x40);
606 bcm43xx_phy_write(dev, BCM43xx_PHY_DACCTL,
607 bcm43xx_phy_read(dev, BCM43xx_PHY_DACCTL)
608 | 0x40);
609 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x14),
610 bcm43xx_phy_read(dev, BCM43xx_PHY_BASE(0x14))
611 | 0x200);
612 }
613 if (phy->type == BCM43xx_PHYTYPE_B &&
614 phy->radio_ver == 0x2050 &&
615 phy->radio_rev < 6) {
616 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x16), 0x410);
617 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x17), 0x820);
618 }
619 if (!lo->rebuild && has_hardware_pctl(phy))
620 lo_read_power_vector(dev);
621 if (phy->rev >= 2) {
622 sav->phy_analogover = bcm43xx_phy_read(dev, BCM43xx_PHY_ANALOGOVER);
623 sav->phy_analogoverval = bcm43xx_phy_read(dev, BCM43xx_PHY_ANALOGOVERVAL);
624 sav->phy_rfover = bcm43xx_phy_read(dev, BCM43xx_PHY_RFOVER);
625 sav->phy_rfoverval = bcm43xx_phy_read(dev, BCM43xx_PHY_RFOVERVAL);
626 sav->phy_classctl = bcm43xx_phy_read(dev, BCM43xx_PHY_CLASSCTL);
627 sav->phy_base_3E = bcm43xx_phy_read(dev, BCM43xx_PHY_BASE(0x3E));
628 sav->phy_crs0 = bcm43xx_phy_read(dev, BCM43xx_PHY_CRS0);
629
630 bcm43xx_phy_write(dev, BCM43xx_PHY_CLASSCTL,
631 bcm43xx_phy_read(dev, BCM43xx_PHY_CLASSCTL)
632 & 0xFFFC);
633 bcm43xx_phy_write(dev, BCM43xx_PHY_CRS0,
634 bcm43xx_phy_read(dev, BCM43xx_PHY_CRS0)
635 & 0x7FFF);
636 bcm43xx_phy_write(dev, BCM43xx_PHY_ANALOGOVER,
637 bcm43xx_phy_read(dev, BCM43xx_PHY_ANALOGOVER)
638 | 0x0003);
639 bcm43xx_phy_write(dev, BCM43xx_PHY_ANALOGOVERVAL,
640 bcm43xx_phy_read(dev, BCM43xx_PHY_ANALOGOVERVAL)
641 & 0xFFFC);
642 if (phy->type == BCM43xx_PHYTYPE_G) {
643 if ((phy->rev >= 7) &&
644 (sprom->r1.boardflags_lo & BCM43xx_BFL_EXTLNA)) {
645 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVER, 0x933);
646 } else {
647 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVER, 0x133);
648 }
649 } else {
650 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVER, 0);
651 }
652 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x3E), 0);
653 }
654 sav->reg_3F4 = bcm43xx_read16(dev, 0x3F4);
655 sav->reg_3E2 = bcm43xx_read16(dev, 0x3E2);
656 sav->radio_43 = bcm43xx_radio_read16(dev, 0x43);
657 sav->radio_7A = bcm43xx_radio_read16(dev, 0x7A);
658 sav->phy_pgactl = bcm43xx_phy_read(dev, BCM43xx_PHY_PGACTL);
659 sav->phy_base_2A = bcm43xx_phy_read(dev, BCM43xx_PHY_BASE(0x2A));
660 sav->phy_syncctl = bcm43xx_phy_read(dev, BCM43xx_PHY_SYNCCTL);
661 sav->phy_dacctl = bcm43xx_phy_read(dev, BCM43xx_PHY_DACCTL);
662
663 if (!has_tx_magnification(phy)) {
664 sav->radio_52 = bcm43xx_radio_read16(dev, 0x52);
665 sav->radio_52 &= 0x00F0;
666 }
667 if (phy->type == BCM43xx_PHYTYPE_B) {
668 sav->phy_base_30 = bcm43xx_phy_read(dev, BCM43xx_PHY_BASE(0x30));
669 sav->phy_base_06 = bcm43xx_phy_read(dev, BCM43xx_PHY_BASE(0x06));
670 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x30), 0x00FF);
671 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x06), 0x3F3F);
672 } else {
673 bcm43xx_write16(dev, 0x3E2,
674 bcm43xx_read16(dev, 0x3E2)
675 | 0x8000);
676 }
677 bcm43xx_write16(dev, 0x3F4,
678 bcm43xx_read16(dev, 0x3F4)
679 & 0xF000);
680
681 tmp = (phy->type == BCM43xx_PHYTYPE_G) ? BCM43xx_PHY_LO_MASK : BCM43xx_PHY_BASE(0x2E);
682 bcm43xx_phy_write(dev, tmp, 0x007F);
683
684 tmp = sav->phy_syncctl;
685 bcm43xx_phy_write(dev, BCM43xx_PHY_SYNCCTL, tmp & 0xFF7F);
686 tmp = sav->radio_7A;
687 bcm43xx_radio_write16(dev, 0x007A, tmp & 0xFFF0);
688
689 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x2A), 0x8A3);
690 if (phy->type == BCM43xx_PHYTYPE_G ||
691 (phy->type == BCM43xx_PHYTYPE_B &&
692 phy->radio_ver == 0x2050 &&
693 phy->radio_rev >= 6)) {
694 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x2B), 0x1003);
695 } else
696 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x2B), 0x0802);
697 if (phy->rev >= 2)
698 bcm43xx_dummy_transmission(dev);
699 bcm43xx_radio_selectchannel(dev, 6, 0);
700 bcm43xx_radio_read16(dev, 0x51); /* dummy read */
701 if (phy->type == BCM43xx_PHYTYPE_G)
702 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x2F), 0);
703 if (lo->rebuild)
704 lo_measure_txctl_values(dev);
705 if (phy->type == BCM43xx_PHYTYPE_G && phy->rev >= 3) {
706 bcm43xx_phy_write(dev, BCM43xx_PHY_LO_MASK, 0xC078);
707 } else {
708 if (phy->type == BCM43xx_PHYTYPE_B)
709 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x2E), 0x8078);
710 else
711 bcm43xx_phy_write(dev, BCM43xx_PHY_LO_MASK, 0x8078);
712 }
713 }
714
715 static void lo_measure_restore(struct bcm43xx_wldev *dev,
716 struct lo_g_saved_values *sav)
717 {
718 struct bcm43xx_phy *phy = &dev->phy;
719 struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
720 u16 tmp;
721
722 if (phy->rev >= 2) {
723 bcm43xx_phy_write(dev, BCM43xx_PHY_PGACTL, 0xE300);
724 tmp = (phy->pga_gain << 8);
725 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVERVAL, tmp | 0xA0);
726 udelay(5);
727 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVERVAL, tmp | 0xA2);
728 udelay(2);
729 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVERVAL, tmp | 0xA3);
730 } else {
731 tmp = (phy->pga_gain | 0xEFA0);
732 bcm43xx_phy_write(dev, BCM43xx_PHY_PGACTL, tmp);
733 }
734 if (has_hardware_pctl(phy)) {
735 bcm43xx_gphy_dc_lt_init(dev);
736 } else {
737 if (lo->rebuild)
738 bcm43xx_lo_g_adjust_to(dev, 3, 2, 0);
739 else
740 bcm43xx_lo_g_adjust(dev);
741 }
742 if (phy->type == BCM43xx_PHYTYPE_G) {
743 if (phy->rev >= 3)
744 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x2E), 0xC078);
745 else
746 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x2E), 0x8078);
747 if (phy->rev >= 2)
748 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x2F), 0x0202);
749 else
750 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x2F), 0x0101);
751 }
752 bcm43xx_write16(dev, 0x3F4, sav->reg_3F4);
753 bcm43xx_phy_write(dev, BCM43xx_PHY_PGACTL, sav->phy_pgactl);
754 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x2A), sav->phy_base_2A);
755 bcm43xx_phy_write(dev, BCM43xx_PHY_SYNCCTL, sav->phy_syncctl);
756 bcm43xx_phy_write(dev, BCM43xx_PHY_DACCTL, sav->phy_dacctl);
757 bcm43xx_radio_write16(dev, 0x43, sav->radio_43);
758 bcm43xx_radio_write16(dev, 0x7A, sav->radio_7A);
759 if (!has_tx_magnification(phy)) {
760 tmp = sav->radio_52;
761 bcm43xx_radio_write16(dev, 0x52,
762 (bcm43xx_radio_read16(dev, 0x52)
763 & 0xFF0F) | tmp);
764 }
765 bcm43xx_write16(dev, 0x3E2, sav->reg_3E2);
766 if (phy->type == BCM43xx_PHYTYPE_B &&
767 phy->radio_ver == 0x2050 &&
768 phy->radio_rev <= 5) {
769 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x30), sav->phy_base_30);
770 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x06), sav->phy_base_06);
771 }
772 if (phy->rev >= 2) {
773 bcm43xx_phy_write(dev, BCM43xx_PHY_ANALOGOVER, sav->phy_analogover);
774 bcm43xx_phy_write(dev, BCM43xx_PHY_ANALOGOVERVAL, sav->phy_analogoverval);
775 bcm43xx_phy_write(dev, BCM43xx_PHY_CLASSCTL, sav->phy_classctl);
776 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVER, sav->phy_rfover);
777 bcm43xx_phy_write(dev, BCM43xx_PHY_RFOVERVAL, sav->phy_rfoverval);
778 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x3E), sav->phy_base_3E);
779 bcm43xx_phy_write(dev, BCM43xx_PHY_CRS0, sav->phy_crs0);
780 }
781 if (has_hardware_pctl(phy)) {
782 tmp = (sav->phy_lo_mask & 0xBFFF);
783 bcm43xx_phy_write(dev, BCM43xx_PHY_LO_MASK, tmp);
784 bcm43xx_phy_write(dev, BCM43xx_PHY_EXTG(0x01), sav->phy_extg_01);
785 bcm43xx_phy_write(dev, BCM43xx_PHY_DACCTL, sav->phy_dacctl_hwpctl);
786 bcm43xx_phy_write(dev, BCM43xx_PHY_BASE(0x14), sav->phy_base_14);
787 bcm43xx_phy_write(dev, BCM43xx_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
788 }
789 bcm43xx_radio_selectchannel(dev, sav->old_channel, 1);
790 }
791
792 struct bcm43xx_lo_g_statemachine {
793 int current_state;
794 int nr_measured;
795 int state_val_multiplier;
796 u16 lowest_feedth;
797 struct bcm43xx_loctl min_loctl;
798 };
799
800 /* Loop over each possible value in this state. */
801 static int lo_probe_possible_loctls(struct bcm43xx_wldev *dev,
802 struct bcm43xx_loctl *probe_loctl,
803 struct bcm43xx_lo_g_statemachine *d)
804 {
805 struct bcm43xx_phy *phy = &dev->phy;
806 struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
807 struct bcm43xx_loctl test_loctl;
808 struct bcm43xx_loctl orig_loctl;
809 struct bcm43xx_loctl prev_loctl = {
810 .i = -100,
811 .q = -100,
812 };
813 int i;
814 int begin, end;
815 int found_lower = 0;
816 u16 feedth;
817
818 static const struct bcm43xx_loctl modifiers[] = {
819 { .i = 1, .q = 1, },
820 { .i = 1, .q = 0, },
821 { .i = 1, .q = -1, },
822 { .i = 0, .q = -1, },
823 { .i = -1, .q = -1, },
824 { .i = -1, .q = 0, },
825 { .i = -1, .q = 1, },
826 { .i = 0, .q = 1, },
827 };
828
829 if (d->current_state == 0) {
830 begin = 1;
831 end = 8;
832 } else if (d->current_state % 2 == 0) {
833 begin = d->current_state - 1;
834 end = d->current_state + 1;
835 } else {
836 begin = d->current_state - 2;
837 end = d->current_state + 2;
838 }
839 if (begin < 1)
840 begin += 8;
841 if (end > 8)
842 end -= 8;
843
844 memcpy(&orig_loctl, probe_loctl, sizeof(struct bcm43xx_loctl));
845 i = begin;
846 d->current_state = i;
847 while (1) {
848 assert(i >= 1 && i <= 8);
849 memcpy(&test_loctl, &orig_loctl, sizeof(struct bcm43xx_loctl));
850 test_loctl.i += modifiers[i - 1].i * d->state_val_multiplier;
851 test_loctl.q += modifiers[i - 1].q * d->state_val_multiplier;
852 if ((test_loctl.i != prev_loctl.i ||
853 test_loctl.q != prev_loctl.q) &&
854 (abs(test_loctl.i) <= 16 &&
855 abs(test_loctl.q) <= 16)) {
856 bcm43xx_lo_write(dev, &test_loctl);
857 feedth = lo_measure_feedthrough(dev, phy->lna_gain,
858 phy->pga_gain,
859 phy->trsw_rx_gain);
860 if (feedth < d->lowest_feedth) {
861 memcpy(probe_loctl, &test_loctl, sizeof(struct bcm43xx_loctl));
862 found_lower = 1;
863 d->lowest_feedth = feedth;
864 if ((d->nr_measured < 2) &&
865 (!has_loopback_gain(phy) || lo->rebuild))
866 break;
867 }
868 }
869 memcpy(&prev_loctl, &test_loctl, sizeof(prev_loctl));
870 if (i == end)
871 break;
872 if (i == 8)
873 i = 1;
874 else
875 i++;
876 d->current_state = i;
877 }
878
879 return found_lower;
880 }
881
882 static void lo_probe_loctls_statemachine(struct bcm43xx_wldev *dev,
883 struct bcm43xx_loctl *loctl,
884 int *max_rx_gain)
885 {
886 struct bcm43xx_phy *phy = &dev->phy;
887 struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
888 struct bcm43xx_lo_g_statemachine d;
889 u16 feedth;
890 int found_lower;
891 struct bcm43xx_loctl probe_loctl;
892 int max_repeat = 1, repeat_cnt = 0;
893
894 d.nr_measured = 0;
895 d.state_val_multiplier = 1;
896 if (has_loopback_gain(phy) && !lo->rebuild)
897 d.state_val_multiplier = 3;
898
899 memcpy(&d.min_loctl, loctl, sizeof(struct bcm43xx_loctl));
900 if (has_loopback_gain(phy) && lo->rebuild)
901 max_repeat = 4;
902 do {
903 bcm43xx_lo_write(dev, &d.min_loctl);
904 feedth = lo_measure_feedthrough(dev, phy->lna_gain,
905 phy->pga_gain,
906 phy->trsw_rx_gain);
907 if (!lo->rebuild && feedth < 0x258) {
908 if (feedth >= 0x12C)
909 *max_rx_gain += 6;
910 else
911 *max_rx_gain += 3;
912 feedth = lo_measure_feedthrough(dev, phy->lna_gain,
913 phy->pga_gain,
914 phy->trsw_rx_gain);
915 }
916 d.lowest_feedth = feedth;
917
918 d.current_state = 0;
919 do {
920 assert(d.current_state >= 0 && d.current_state <= 8);
921 memcpy(&probe_loctl, &d.min_loctl, sizeof(struct bcm43xx_loctl));
922 found_lower = lo_probe_possible_loctls(dev, &probe_loctl, &d);
923 if (!found_lower)
924 break;
925 if ((probe_loctl.i == d.min_loctl.i) &&
926 (probe_loctl.q == d.min_loctl.q))
927 break;
928 memcpy(&d.min_loctl, &probe_loctl, sizeof(struct bcm43xx_loctl));
929 d.nr_measured++;
930 } while (d.nr_measured < 24);
931 memcpy(loctl, &d.min_loctl, sizeof(struct bcm43xx_loctl));
932
933 if (has_loopback_gain(phy)) {
934 if (d.lowest_feedth > 0x1194)
935 *max_rx_gain -= 6;
936 else if (d.lowest_feedth < 0x5DC)
937 *max_rx_gain += 3;
938 if (repeat_cnt == 0) {
939 if (d.lowest_feedth <= 0x5DC) {
940 d.state_val_multiplier = 1;
941 repeat_cnt++;
942 } else
943 d.state_val_multiplier = 2;
944 } else if (repeat_cnt == 2)
945 d.state_val_multiplier = 1;
946 }
947 lo_measure_gain_values(dev, *max_rx_gain, has_loopback_gain(phy));
948 } while (++repeat_cnt < max_repeat);
949 }
950
951 static void lo_measure(struct bcm43xx_wldev *dev)
952 {
953 struct bcm43xx_phy *phy = &dev->phy;
954 struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
955 struct bcm43xx_loctl loctl = {
956 .i = 0,
957 .q = 0,
958 };
959 struct bcm43xx_loctl *ploctl;
960 int max_rx_gain;
961 int rfidx, bbidx;
962
963 /* Values from the "TXCTL Register and Value Table" */
964 u16 txctl_reg;
965 u16 txctl_value;
966 u16 pad_mix_gain;
967
968 txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain);
969
970 for (rfidx = 0; rfidx < lo->rfatt_list.len; rfidx++) {
971
972 bcm43xx_radio_write16(dev, 0x43,
973 (bcm43xx_radio_read16(dev, 0x43)
974 & 0xFFF0) | lo->rfatt_list.list[rfidx].att);
975 bcm43xx_radio_write16(dev, txctl_reg,
976 (bcm43xx_radio_read16(dev, txctl_reg)
977 & ~txctl_value)
978 | (lo->rfatt_list.list[rfidx].with_padmix ? txctl_value : 0));
979
980 for (bbidx = 0; bbidx < lo->bbatt_list.len; bbidx++) {
981 if (lo->rebuild) {
982 ploctl = bcm43xx_get_lo_g_ctl_nopadmix(dev,
983 &lo->rfatt_list.list[rfidx],
984 &lo->bbatt_list.list[bbidx]);
985 } else {
986 ploctl = bcm43xx_get_lo_g_ctl(dev, &lo->rfatt_list.list[rfidx],
987 &lo->bbatt_list.list[bbidx]);
988 if (!ploctl->used)
989 continue;
990 }
991 memcpy(&loctl, ploctl, sizeof(loctl));
992
993 max_rx_gain = lo->rfatt_list.list[rfidx].att * 2;
994 max_rx_gain += lo->bbatt_list.list[bbidx].att / 2;
995 if (lo->rfatt_list.list[rfidx].with_padmix)
996 max_rx_gain -= pad_mix_gain;
997 if (has_loopback_gain(phy))
998 max_rx_gain += phy->max_lb_gain;
999 lo_measure_gain_values(dev, max_rx_gain, has_loopback_gain(phy));
1000
1001 bcm43xx_phy_set_baseband_attenuation(dev, lo->bbatt_list.list[bbidx].att);
1002 lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
1003 if (phy->type == BCM43xx_PHYTYPE_B) {
1004 loctl.i++;
1005 loctl.q++;
1006 }
1007 memcpy(ploctl, &loctl, sizeof(loctl));
1008 }
1009 }
1010 }
1011
1012 #if BCM43xx_DEBUG
1013 static void do_validate_loctl(struct bcm43xx_wldev *dev,
1014 struct bcm43xx_loctl *control)
1015 {
1016 const int is_initializing = (bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZING);
1017
1018 if (unlikely(abs(control->i) > 16 ||
1019 abs(control->q) > 16 ||
1020 (is_initializing && control->used))) {
1021 printk(KERN_ERR PFX "ERROR: LO control pair validation failed "
1022 "(first: %d, second: %d, used %u)\n",
1023 control->i, control->q, control->used);
1024 }
1025 }
1026 static void validate_all_loctls(struct bcm43xx_wldev *dev)
1027 {
1028 bcm43xx_call_for_each_loctl(dev, do_validate_loctl);
1029 }
1030 #else /* BCM43xx_DEBUG */
1031 static inline void validate_all_loctls(struct bcm43xx_wldev *dev) { }
1032 #endif /* BCM43xx_DEBUG */
1033
1034 void bcm43xx_lo_g_measure(struct bcm43xx_wldev *dev)
1035 {
1036 struct bcm43xx_phy *phy = &dev->phy;
1037 struct lo_g_saved_values sav;
1038
1039 assert(phy->type == BCM43xx_PHYTYPE_B ||
1040 phy->type == BCM43xx_PHYTYPE_G);
1041
1042 sav.old_channel = phy->channel;
1043 lo_measure_setup(dev, &sav);
1044 lo_measure(dev);
1045 lo_measure_restore(dev, &sav);
1046
1047 validate_all_loctls(dev);
1048
1049 phy->lo_control->lo_measured = 1;
1050 phy->lo_control->rebuild = 0;
1051 }
1052
1053 void bcm43xx_lo_g_adjust(struct bcm43xx_wldev *dev)
1054 {
1055 bcm43xx_lo_write(dev, bcm43xx_lo_g_ctl_current(dev));
1056 }
1057
1058 static inline void fixup_rfatt_for_txcontrol(struct bcm43xx_rfatt *rf,
1059 u8 tx_control)
1060 {
1061 if (tx_control & BCM43xx_TXCTL_TXMIX) {
1062 if (rf->att < 5)
1063 rf->att = 4;
1064 }
1065 }
1066
1067 void bcm43xx_lo_g_adjust_to(struct bcm43xx_wldev *dev,
1068 u16 rfatt, u16 bbatt, u16 tx_control)
1069 {
1070 struct bcm43xx_rfatt rf;
1071 struct bcm43xx_bbatt bb;
1072 struct bcm43xx_loctl *loctl;
1073
1074 memset(&rf, 0, sizeof(rf));
1075 memset(&bb, 0, sizeof(bb));
1076 rf.att = rfatt;
1077 bb.att = bbatt;
1078 fixup_rfatt_for_txcontrol(&rf, tx_control);
1079 loctl = bcm43xx_get_lo_g_ctl(dev, &rf, &bb);
1080 bcm43xx_lo_write(dev, loctl);
1081 }
1082
1083 struct bcm43xx_loctl * bcm43xx_lo_g_ctl_current(struct bcm43xx_wldev *dev)
1084 {
1085 struct bcm43xx_phy *phy = &dev->phy;
1086 struct bcm43xx_rfatt rf;
1087
1088 memcpy(&rf, &phy->rfatt, sizeof(rf));
1089 fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
1090
1091 return bcm43xx_get_lo_g_ctl(dev, &rf, &phy->bbatt);
1092 }
1093
1094 static void do_mark_unused(struct bcm43xx_wldev *dev,
1095 struct bcm43xx_loctl *control)
1096 {
1097 control->used = 0;
1098 }
1099
1100 void bcm43xx_lo_g_ctl_mark_all_unused(struct bcm43xx_wldev *dev)
1101 {
1102 struct bcm43xx_phy *phy = &dev->phy;
1103 struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
1104
1105 bcm43xx_call_for_each_loctl(dev, do_mark_unused);
1106 lo->rebuild = 1;
1107 }
1108
1109 void bcm43xx_lo_g_ctl_mark_cur_used(struct bcm43xx_wldev *dev)
1110 {
1111 bcm43xx_lo_g_ctl_current(dev)->used = 1;
1112 }