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