Merge bcm43xx-mac80211 driver from tree at bu3sch.de, pulled 24/6
[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 #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 }