]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
Merge remote-tracking branch 'regulator/topic/max8997' into regulator-next
[karo-tx-linux.git] / drivers / net / wireless / brcm80211 / brcmsmac / phy / phy_lcn.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/delay.h>
19 #include <linux/cordic.h>
20
21 #include <pmu.h>
22 #include <d11.h>
23 #include <phy_shim.h>
24 #include "phy_qmath.h"
25 #include "phy_hal.h"
26 #include "phy_radio.h"
27 #include "phytbl_lcn.h"
28 #include "phy_lcn.h"
29
30 #define PLL_2064_NDIV           90
31 #define PLL_2064_LOW_END_VCO    3000
32 #define PLL_2064_LOW_END_KVCO   27
33 #define PLL_2064_HIGH_END_VCO   4200
34 #define PLL_2064_HIGH_END_KVCO  68
35 #define PLL_2064_LOOP_BW_DOUBLER        200
36 #define PLL_2064_D30_DOUBLER            10500
37 #define PLL_2064_LOOP_BW        260
38 #define PLL_2064_D30            8000
39 #define PLL_2064_CAL_REF_TO     8
40 #define PLL_2064_MHZ            1000000
41 #define PLL_2064_OPEN_LOOP_DELAY        5
42
43 #define TEMPSENSE                       1
44 #define VBATSENSE           2
45
46 #define NOISE_IF_UPD_CHK_INTERVAL       1
47 #define NOISE_IF_UPD_RST_INTERVAL       60
48 #define NOISE_IF_UPD_THRESHOLD_CNT      1
49 #define NOISE_IF_UPD_TRHRESHOLD 50
50 #define NOISE_IF_UPD_TIMEOUT            1000
51 #define NOISE_IF_OFF                    0
52 #define NOISE_IF_CHK                    1
53 #define NOISE_IF_ON                     2
54
55 #define PAPD_BLANKING_PROFILE           3
56 #define PAPD2LUT                        0
57 #define PAPD_CORR_NORM                  0
58 #define PAPD_BLANKING_THRESHOLD         0
59 #define PAPD_STOP_AFTER_LAST_UPDATE     0
60
61 #define LCN_TARGET_PWR  60
62
63 #define LCN_VBAT_OFFSET_433X 34649679
64 #define LCN_VBAT_SLOPE_433X  8258032
65
66 #define LCN_VBAT_SCALE_NOM  53
67 #define LCN_VBAT_SCALE_DEN  432
68
69 #define LCN_TEMPSENSE_OFFSET  80812
70 #define LCN_TEMPSENSE_DEN  2647
71
72 #define LCN_BW_LMT      200
73 #define LCN_CUR_LMT     1250
74 #define LCN_MULT        1
75 #define LCN_VCO_DIV     30
76 #define LCN_OFFSET      680
77 #define LCN_FACT        490
78 #define LCN_CUR_DIV     2640
79
80 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
81         (0 + 8)
82 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
83         (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)
84
85 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \
86         (0 + 8)
87 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \
88         (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)
89
90 #define wlc_lcnphy_enable_tx_gain_override(pi) \
91         wlc_lcnphy_set_tx_gain_override(pi, true)
92 #define wlc_lcnphy_disable_tx_gain_override(pi) \
93         wlc_lcnphy_set_tx_gain_override(pi, false)
94
95 #define wlc_lcnphy_iqcal_active(pi)     \
96         (read_phy_reg((pi), 0x451) & \
97          ((0x1 << 15) | (0x1 << 14)))
98
99 #define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
100 #define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
101         (pi->temppwrctrl_capable)
102 #define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
103         (pi->hwpwrctrl_capable)
104
105 #define SWCTRL_BT_TX            0x18
106 #define SWCTRL_OVR_DISABLE      0x40
107
108 #define AFE_CLK_INIT_MODE_TXRX2X        1
109 #define AFE_CLK_INIT_MODE_PAPD          0
110
111 #define LCNPHY_TBL_ID_IQLOCAL                   0x00
112
113 #define LCNPHY_TBL_ID_RFSEQ         0x08
114 #define LCNPHY_TBL_ID_GAIN_IDX          0x0d
115 #define LCNPHY_TBL_ID_SW_CTRL                   0x0f
116 #define LCNPHY_TBL_ID_GAIN_TBL          0x12
117 #define LCNPHY_TBL_ID_SPUR                      0x14
118 #define LCNPHY_TBL_ID_SAMPLEPLAY                0x15
119 #define LCNPHY_TBL_ID_SAMPLEPLAY1               0x16
120
121 #define LCNPHY_TX_PWR_CTRL_RATE_OFFSET  832
122 #define LCNPHY_TX_PWR_CTRL_MAC_OFFSET   128
123 #define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET  192
124 #define LCNPHY_TX_PWR_CTRL_IQ_OFFSET            320
125 #define LCNPHY_TX_PWR_CTRL_LO_OFFSET            448
126 #define LCNPHY_TX_PWR_CTRL_PWR_OFFSET           576
127
128 #define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313  140
129
130 #define LCNPHY_TX_PWR_CTRL_START_NPT            1
131 #define LCNPHY_TX_PWR_CTRL_MAX_NPT                      7
132
133 #define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
134
135 #define LCNPHY_ACI_DETECT_START      1
136 #define LCNPHY_ACI_DETECT_PROGRESS   2
137 #define LCNPHY_ACI_DETECT_STOP       3
138
139 #define LCNPHY_ACI_CRSHIFRMLO_TRSH 100
140 #define LCNPHY_ACI_GLITCH_TRSH 2000
141 #define LCNPHY_ACI_TMOUT 250
142 #define LCNPHY_ACI_DETECT_TIMEOUT  2
143 #define LCNPHY_ACI_START_DELAY 0
144
145 #define wlc_lcnphy_tx_gain_override_enabled(pi) \
146         (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
147
148 #define wlc_lcnphy_total_tx_frames(pi) \
149         wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \
150                             offsetof(struct macstat, txallfrm))
151
152 struct lcnphy_txgains {
153         u16 gm_gain;
154         u16 pga_gain;
155         u16 pad_gain;
156         u16 dac_gain;
157 };
158
159 enum lcnphy_cal_mode {
160         LCNPHY_CAL_FULL,
161         LCNPHY_CAL_RECAL,
162         LCNPHY_CAL_CURRECAL,
163         LCNPHY_CAL_DIGCAL,
164         LCNPHY_CAL_GCTRL
165 };
166
167 struct lcnphy_rx_iqcomp {
168         u8 chan;
169         s16 a;
170         s16 b;
171 };
172
173 struct lcnphy_spb_tone {
174         s16 re;
175         s16 im;
176 };
177
178 struct lcnphy_unsign16_struct {
179         u16 re;
180         u16 im;
181 };
182
183 struct lcnphy_iq_est {
184         u32 iq_prod;
185         u32 i_pwr;
186         u32 q_pwr;
187 };
188
189 struct lcnphy_sfo_cfg {
190         u16 ptcentreTs20;
191         u16 ptcentreFactor;
192 };
193
194 enum lcnphy_papd_cal_type {
195         LCNPHY_PAPD_CAL_CW,
196         LCNPHY_PAPD_CAL_OFDM
197 };
198
199 typedef u16 iqcal_gain_params_lcnphy[9];
200
201 static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
202         {0, 0, 0, 0, 0, 0, 0, 0, 0},
203 };
204
205 static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
206         tbl_iqcal_gainparams_lcnphy_2G,
207 };
208
209 static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
210         ARRAY_SIZE(tbl_iqcal_gainparams_lcnphy_2G),
211 };
212
213 static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = {
214         {965, 1087},
215         {967, 1085},
216         {969, 1082},
217         {971, 1080},
218         {973, 1078},
219         {975, 1076},
220         {977, 1073},
221         {979, 1071},
222         {981, 1069},
223         {983, 1067},
224         {985, 1065},
225         {987, 1063},
226         {989, 1060},
227         {994, 1055}
228 };
229
230 static const
231 u16 lcnphy_iqcal_loft_gainladder[] = {
232         ((2 << 8) | 0),
233         ((3 << 8) | 0),
234         ((4 << 8) | 0),
235         ((6 << 8) | 0),
236         ((8 << 8) | 0),
237         ((11 << 8) | 0),
238         ((16 << 8) | 0),
239         ((16 << 8) | 1),
240         ((16 << 8) | 2),
241         ((16 << 8) | 3),
242         ((16 << 8) | 4),
243         ((16 << 8) | 5),
244         ((16 << 8) | 6),
245         ((16 << 8) | 7),
246         ((23 << 8) | 7),
247         ((32 << 8) | 7),
248         ((45 << 8) | 7),
249         ((64 << 8) | 7),
250         ((91 << 8) | 7),
251         ((128 << 8) | 7)
252 };
253
254 static const
255 u16 lcnphy_iqcal_ir_gainladder[] = {
256         ((1 << 8) | 0),
257         ((2 << 8) | 0),
258         ((4 << 8) | 0),
259         ((6 << 8) | 0),
260         ((8 << 8) | 0),
261         ((11 << 8) | 0),
262         ((16 << 8) | 0),
263         ((23 << 8) | 0),
264         ((32 << 8) | 0),
265         ((45 << 8) | 0),
266         ((64 << 8) | 0),
267         ((64 << 8) | 1),
268         ((64 << 8) | 2),
269         ((64 << 8) | 3),
270         ((64 << 8) | 4),
271         ((64 << 8) | 5),
272         ((64 << 8) | 6),
273         ((64 << 8) | 7),
274         ((91 << 8) | 7),
275         ((128 << 8) | 7)
276 };
277
278 static const
279 struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = {
280         {88, 0},
281         {73, 49},
282         {34, 81},
283         {-17, 86},
284         {-62, 62},
285         {-86, 17},
286         {-81, -34},
287         {-49, -73},
288         {0, -88},
289         {49, -73},
290         {81, -34},
291         {86, 17},
292         {62, 62},
293         {17, 86},
294         {-34, 81},
295         {-73, 49},
296         {-88, 0},
297         {-73, -49},
298         {-34, -81},
299         {17, -86},
300         {62, -62},
301         {86, -17},
302         {81, 34},
303         {49, 73},
304         {0, 88},
305         {-49, 73},
306         {-81, 34},
307         {-86, -17},
308         {-62, -62},
309         {-17, -86},
310         {34, -81},
311         {73, -49},
312 };
313
314 static const
315 u16 iqlo_loopback_rf_regs[20] = {
316         RADIO_2064_REG036,
317         RADIO_2064_REG11A,
318         RADIO_2064_REG03A,
319         RADIO_2064_REG025,
320         RADIO_2064_REG028,
321         RADIO_2064_REG005,
322         RADIO_2064_REG112,
323         RADIO_2064_REG0FF,
324         RADIO_2064_REG11F,
325         RADIO_2064_REG00B,
326         RADIO_2064_REG113,
327         RADIO_2064_REG007,
328         RADIO_2064_REG0FC,
329         RADIO_2064_REG0FD,
330         RADIO_2064_REG012,
331         RADIO_2064_REG057,
332         RADIO_2064_REG059,
333         RADIO_2064_REG05C,
334         RADIO_2064_REG078,
335         RADIO_2064_REG092,
336 };
337
338 static const
339 u16 tempsense_phy_regs[14] = {
340         0x503,
341         0x4a4,
342         0x4d0,
343         0x4d9,
344         0x4da,
345         0x4a6,
346         0x938,
347         0x939,
348         0x4d8,
349         0x4d0,
350         0x4d7,
351         0x4a5,
352         0x40d,
353         0x4a2,
354 };
355
356 static const
357 u16 rxiq_cal_rf_reg[11] = {
358         RADIO_2064_REG098,
359         RADIO_2064_REG116,
360         RADIO_2064_REG12C,
361         RADIO_2064_REG06A,
362         RADIO_2064_REG00B,
363         RADIO_2064_REG01B,
364         RADIO_2064_REG113,
365         RADIO_2064_REG01D,
366         RADIO_2064_REG114,
367         RADIO_2064_REG02E,
368         RADIO_2064_REG12A,
369 };
370
371 static const
372 struct lcnphy_rx_iqcomp lcnphy_rx_iqcomp_table_rev0[] = {
373         {1, 0, 0},
374         {2, 0, 0},
375         {3, 0, 0},
376         {4, 0, 0},
377         {5, 0, 0},
378         {6, 0, 0},
379         {7, 0, 0},
380         {8, 0, 0},
381         {9, 0, 0},
382         {10, 0, 0},
383         {11, 0, 0},
384         {12, 0, 0},
385         {13, 0, 0},
386         {14, 0, 0},
387         {34, 0, 0},
388         {38, 0, 0},
389         {42, 0, 0},
390         {46, 0, 0},
391         {36, 0, 0},
392         {40, 0, 0},
393         {44, 0, 0},
394         {48, 0, 0},
395         {52, 0, 0},
396         {56, 0, 0},
397         {60, 0, 0},
398         {64, 0, 0},
399         {100, 0, 0},
400         {104, 0, 0},
401         {108, 0, 0},
402         {112, 0, 0},
403         {116, 0, 0},
404         {120, 0, 0},
405         {124, 0, 0},
406         {128, 0, 0},
407         {132, 0, 0},
408         {136, 0, 0},
409         {140, 0, 0},
410         {149, 0, 0},
411         {153, 0, 0},
412         {157, 0, 0},
413         {161, 0, 0},
414         {165, 0, 0},
415         {184, 0, 0},
416         {188, 0, 0},
417         {192, 0, 0},
418         {196, 0, 0},
419         {200, 0, 0},
420         {204, 0, 0},
421         {208, 0, 0},
422         {212, 0, 0},
423         {216, 0, 0},
424 };
425
426 static const u32 lcnphy_23bitgaincode_table[] = {
427         0x200100,
428         0x200200,
429         0x200004,
430         0x200014,
431         0x200024,
432         0x200034,
433         0x200134,
434         0x200234,
435         0x200334,
436         0x200434,
437         0x200037,
438         0x200137,
439         0x200237,
440         0x200337,
441         0x200437,
442         0x000035,
443         0x000135,
444         0x000235,
445         0x000037,
446         0x000137,
447         0x000237,
448         0x000337,
449         0x00013f,
450         0x00023f,
451         0x00033f,
452         0x00034f,
453         0x00044f,
454         0x00144f,
455         0x00244f,
456         0x00254f,
457         0x00354f,
458         0x00454f,
459         0x00464f,
460         0x01464f,
461         0x02464f,
462         0x03464f,
463         0x04464f,
464 };
465
466 static const s8 lcnphy_gain_table[] = {
467         -16,
468         -13,
469         10,
470         7,
471         4,
472         0,
473         3,
474         6,
475         9,
476         12,
477         15,
478         18,
479         21,
480         24,
481         27,
482         30,
483         33,
484         36,
485         39,
486         42,
487         45,
488         48,
489         50,
490         53,
491         56,
492         59,
493         62,
494         65,
495         68,
496         71,
497         74,
498         77,
499         80,
500         83,
501         86,
502         89,
503         92,
504 };
505
506 static const s8 lcnphy_gain_index_offset_for_rssi[] = {
507         7,
508         7,
509         7,
510         7,
511         7,
512         7,
513         7,
514         8,
515         7,
516         7,
517         6,
518         7,
519         7,
520         4,
521         4,
522         4,
523         4,
524         4,
525         4,
526         4,
527         4,
528         3,
529         3,
530         3,
531         3,
532         3,
533         3,
534         4,
535         2,
536         2,
537         2,
538         2,
539         2,
540         2,
541         -1,
542         -2,
543         -2,
544         -2
545 };
546
547 struct chan_info_2064_lcnphy {
548         uint chan;
549         uint freq;
550         u8 logen_buftune;
551         u8 logen_rccr_tx;
552         u8 txrf_mix_tune_ctrl;
553         u8 pa_input_tune_g;
554         u8 logen_rccr_rx;
555         u8 pa_rxrf_lna1_freq_tune;
556         u8 pa_rxrf_lna2_freq_tune;
557         u8 rxrf_rxrf_spare1;
558 };
559
560 static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {
561         {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
562         {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
563         {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
564         {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
565         {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
566         {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
567         {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
568         {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
569         {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
570         {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
571         {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
572         {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
573         {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
574         {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
575 };
576
577 static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {
578         {0x00, 0, 0, 0, 0},
579         {0x01, 0x64, 0x64, 0, 0},
580         {0x02, 0x20, 0x20, 0, 0},
581         {0x03, 0x66, 0x66, 0, 0},
582         {0x04, 0xf8, 0xf8, 0, 0},
583         {0x05, 0, 0, 0, 0},
584         {0x06, 0x10, 0x10, 0, 0},
585         {0x07, 0, 0, 0, 0},
586         {0x08, 0, 0, 0, 0},
587         {0x09, 0, 0, 0, 0},
588         {0x0A, 0x37, 0x37, 0, 0},
589         {0x0B, 0x6, 0x6, 0, 0},
590         {0x0C, 0x55, 0x55, 0, 0},
591         {0x0D, 0x8b, 0x8b, 0, 0},
592         {0x0E, 0, 0, 0, 0},
593         {0x0F, 0x5, 0x5, 0, 0},
594         {0x10, 0, 0, 0, 0},
595         {0x11, 0xe, 0xe, 0, 0},
596         {0x12, 0, 0, 0, 0},
597         {0x13, 0xb, 0xb, 0, 0},
598         {0x14, 0x2, 0x2, 0, 0},
599         {0x15, 0x12, 0x12, 0, 0},
600         {0x16, 0x12, 0x12, 0, 0},
601         {0x17, 0xc, 0xc, 0, 0},
602         {0x18, 0xc, 0xc, 0, 0},
603         {0x19, 0xc, 0xc, 0, 0},
604         {0x1A, 0x8, 0x8, 0, 0},
605         {0x1B, 0x2, 0x2, 0, 0},
606         {0x1C, 0, 0, 0, 0},
607         {0x1D, 0x1, 0x1, 0, 0},
608         {0x1E, 0x12, 0x12, 0, 0},
609         {0x1F, 0x6e, 0x6e, 0, 0},
610         {0x20, 0x2, 0x2, 0, 0},
611         {0x21, 0x23, 0x23, 0, 0},
612         {0x22, 0x8, 0x8, 0, 0},
613         {0x23, 0, 0, 0, 0},
614         {0x24, 0, 0, 0, 0},
615         {0x25, 0xc, 0xc, 0, 0},
616         {0x26, 0x33, 0x33, 0, 0},
617         {0x27, 0x55, 0x55, 0, 0},
618         {0x28, 0, 0, 0, 0},
619         {0x29, 0x30, 0x30, 0, 0},
620         {0x2A, 0xb, 0xb, 0, 0},
621         {0x2B, 0x1b, 0x1b, 0, 0},
622         {0x2C, 0x3, 0x3, 0, 0},
623         {0x2D, 0x1b, 0x1b, 0, 0},
624         {0x2E, 0, 0, 0, 0},
625         {0x2F, 0x20, 0x20, 0, 0},
626         {0x30, 0xa, 0xa, 0, 0},
627         {0x31, 0, 0, 0, 0},
628         {0x32, 0x62, 0x62, 0, 0},
629         {0x33, 0x19, 0x19, 0, 0},
630         {0x34, 0x33, 0x33, 0, 0},
631         {0x35, 0x77, 0x77, 0, 0},
632         {0x36, 0, 0, 0, 0},
633         {0x37, 0x70, 0x70, 0, 0},
634         {0x38, 0x3, 0x3, 0, 0},
635         {0x39, 0xf, 0xf, 0, 0},
636         {0x3A, 0x6, 0x6, 0, 0},
637         {0x3B, 0xcf, 0xcf, 0, 0},
638         {0x3C, 0x1a, 0x1a, 0, 0},
639         {0x3D, 0x6, 0x6, 0, 0},
640         {0x3E, 0x42, 0x42, 0, 0},
641         {0x3F, 0, 0, 0, 0},
642         {0x40, 0xfb, 0xfb, 0, 0},
643         {0x41, 0x9a, 0x9a, 0, 0},
644         {0x42, 0x7a, 0x7a, 0, 0},
645         {0x43, 0x29, 0x29, 0, 0},
646         {0x44, 0, 0, 0, 0},
647         {0x45, 0x8, 0x8, 0, 0},
648         {0x46, 0xce, 0xce, 0, 0},
649         {0x47, 0x27, 0x27, 0, 0},
650         {0x48, 0x62, 0x62, 0, 0},
651         {0x49, 0x6, 0x6, 0, 0},
652         {0x4A, 0x58, 0x58, 0, 0},
653         {0x4B, 0xf7, 0xf7, 0, 0},
654         {0x4C, 0, 0, 0, 0},
655         {0x4D, 0xb3, 0xb3, 0, 0},
656         {0x4E, 0, 0, 0, 0},
657         {0x4F, 0x2, 0x2, 0, 0},
658         {0x50, 0, 0, 0, 0},
659         {0x51, 0x9, 0x9, 0, 0},
660         {0x52, 0x5, 0x5, 0, 0},
661         {0x53, 0x17, 0x17, 0, 0},
662         {0x54, 0x38, 0x38, 0, 0},
663         {0x55, 0, 0, 0, 0},
664         {0x56, 0, 0, 0, 0},
665         {0x57, 0xb, 0xb, 0, 0},
666         {0x58, 0, 0, 0, 0},
667         {0x59, 0, 0, 0, 0},
668         {0x5A, 0, 0, 0, 0},
669         {0x5B, 0, 0, 0, 0},
670         {0x5C, 0, 0, 0, 0},
671         {0x5D, 0, 0, 0, 0},
672         {0x5E, 0x88, 0x88, 0, 0},
673         {0x5F, 0xcc, 0xcc, 0, 0},
674         {0x60, 0x74, 0x74, 0, 0},
675         {0x61, 0x74, 0x74, 0, 0},
676         {0x62, 0x74, 0x74, 0, 0},
677         {0x63, 0x44, 0x44, 0, 0},
678         {0x64, 0x77, 0x77, 0, 0},
679         {0x65, 0x44, 0x44, 0, 0},
680         {0x66, 0x77, 0x77, 0, 0},
681         {0x67, 0x55, 0x55, 0, 0},
682         {0x68, 0x77, 0x77, 0, 0},
683         {0x69, 0x77, 0x77, 0, 0},
684         {0x6A, 0, 0, 0, 0},
685         {0x6B, 0x7f, 0x7f, 0, 0},
686         {0x6C, 0x8, 0x8, 0, 0},
687         {0x6D, 0, 0, 0, 0},
688         {0x6E, 0x88, 0x88, 0, 0},
689         {0x6F, 0x66, 0x66, 0, 0},
690         {0x70, 0x66, 0x66, 0, 0},
691         {0x71, 0x28, 0x28, 0, 0},
692         {0x72, 0x55, 0x55, 0, 0},
693         {0x73, 0x4, 0x4, 0, 0},
694         {0x74, 0, 0, 0, 0},
695         {0x75, 0, 0, 0, 0},
696         {0x76, 0, 0, 0, 0},
697         {0x77, 0x1, 0x1, 0, 0},
698         {0x78, 0xd6, 0xd6, 0, 0},
699         {0x79, 0, 0, 0, 0},
700         {0x7A, 0, 0, 0, 0},
701         {0x7B, 0, 0, 0, 0},
702         {0x7C, 0, 0, 0, 0},
703         {0x7D, 0, 0, 0, 0},
704         {0x7E, 0, 0, 0, 0},
705         {0x7F, 0, 0, 0, 0},
706         {0x80, 0, 0, 0, 0},
707         {0x81, 0, 0, 0, 0},
708         {0x82, 0, 0, 0, 0},
709         {0x83, 0xb4, 0xb4, 0, 0},
710         {0x84, 0x1, 0x1, 0, 0},
711         {0x85, 0x20, 0x20, 0, 0},
712         {0x86, 0x5, 0x5, 0, 0},
713         {0x87, 0xff, 0xff, 0, 0},
714         {0x88, 0x7, 0x7, 0, 0},
715         {0x89, 0x77, 0x77, 0, 0},
716         {0x8A, 0x77, 0x77, 0, 0},
717         {0x8B, 0x77, 0x77, 0, 0},
718         {0x8C, 0x77, 0x77, 0, 0},
719         {0x8D, 0x8, 0x8, 0, 0},
720         {0x8E, 0xa, 0xa, 0, 0},
721         {0x8F, 0x8, 0x8, 0, 0},
722         {0x90, 0x18, 0x18, 0, 0},
723         {0x91, 0x5, 0x5, 0, 0},
724         {0x92, 0x1f, 0x1f, 0, 0},
725         {0x93, 0x10, 0x10, 0, 0},
726         {0x94, 0x3, 0x3, 0, 0},
727         {0x95, 0, 0, 0, 0},
728         {0x96, 0, 0, 0, 0},
729         {0x97, 0xaa, 0xaa, 0, 0},
730         {0x98, 0, 0, 0, 0},
731         {0x99, 0x23, 0x23, 0, 0},
732         {0x9A, 0x7, 0x7, 0, 0},
733         {0x9B, 0xf, 0xf, 0, 0},
734         {0x9C, 0x10, 0x10, 0, 0},
735         {0x9D, 0x3, 0x3, 0, 0},
736         {0x9E, 0x4, 0x4, 0, 0},
737         {0x9F, 0x20, 0x20, 0, 0},
738         {0xA0, 0, 0, 0, 0},
739         {0xA1, 0, 0, 0, 0},
740         {0xA2, 0, 0, 0, 0},
741         {0xA3, 0, 0, 0, 0},
742         {0xA4, 0x1, 0x1, 0, 0},
743         {0xA5, 0x77, 0x77, 0, 0},
744         {0xA6, 0x77, 0x77, 0, 0},
745         {0xA7, 0x77, 0x77, 0, 0},
746         {0xA8, 0x77, 0x77, 0, 0},
747         {0xA9, 0x8c, 0x8c, 0, 0},
748         {0xAA, 0x88, 0x88, 0, 0},
749         {0xAB, 0x78, 0x78, 0, 0},
750         {0xAC, 0x57, 0x57, 0, 0},
751         {0xAD, 0x88, 0x88, 0, 0},
752         {0xAE, 0, 0, 0, 0},
753         {0xAF, 0x8, 0x8, 0, 0},
754         {0xB0, 0x88, 0x88, 0, 0},
755         {0xB1, 0, 0, 0, 0},
756         {0xB2, 0x1b, 0x1b, 0, 0},
757         {0xB3, 0x3, 0x3, 0, 0},
758         {0xB4, 0x24, 0x24, 0, 0},
759         {0xB5, 0x3, 0x3, 0, 0},
760         {0xB6, 0x1b, 0x1b, 0, 0},
761         {0xB7, 0x24, 0x24, 0, 0},
762         {0xB8, 0x3, 0x3, 0, 0},
763         {0xB9, 0, 0, 0, 0},
764         {0xBA, 0xaa, 0xaa, 0, 0},
765         {0xBB, 0, 0, 0, 0},
766         {0xBC, 0x4, 0x4, 0, 0},
767         {0xBD, 0, 0, 0, 0},
768         {0xBE, 0x8, 0x8, 0, 0},
769         {0xBF, 0x11, 0x11, 0, 0},
770         {0xC0, 0, 0, 0, 0},
771         {0xC1, 0, 0, 0, 0},
772         {0xC2, 0x62, 0x62, 0, 0},
773         {0xC3, 0x1e, 0x1e, 0, 0},
774         {0xC4, 0x33, 0x33, 0, 0},
775         {0xC5, 0x37, 0x37, 0, 0},
776         {0xC6, 0, 0, 0, 0},
777         {0xC7, 0x70, 0x70, 0, 0},
778         {0xC8, 0x1e, 0x1e, 0, 0},
779         {0xC9, 0x6, 0x6, 0, 0},
780         {0xCA, 0x4, 0x4, 0, 0},
781         {0xCB, 0x2f, 0x2f, 0, 0},
782         {0xCC, 0xf, 0xf, 0, 0},
783         {0xCD, 0, 0, 0, 0},
784         {0xCE, 0xff, 0xff, 0, 0},
785         {0xCF, 0x8, 0x8, 0, 0},
786         {0xD0, 0x3f, 0x3f, 0, 0},
787         {0xD1, 0x3f, 0x3f, 0, 0},
788         {0xD2, 0x3f, 0x3f, 0, 0},
789         {0xD3, 0, 0, 0, 0},
790         {0xD4, 0, 0, 0, 0},
791         {0xD5, 0, 0, 0, 0},
792         {0xD6, 0xcc, 0xcc, 0, 0},
793         {0xD7, 0, 0, 0, 0},
794         {0xD8, 0x8, 0x8, 0, 0},
795         {0xD9, 0x8, 0x8, 0, 0},
796         {0xDA, 0x8, 0x8, 0, 0},
797         {0xDB, 0x11, 0x11, 0, 0},
798         {0xDC, 0, 0, 0, 0},
799         {0xDD, 0x87, 0x87, 0, 0},
800         {0xDE, 0x88, 0x88, 0, 0},
801         {0xDF, 0x8, 0x8, 0, 0},
802         {0xE0, 0x8, 0x8, 0, 0},
803         {0xE1, 0x8, 0x8, 0, 0},
804         {0xE2, 0, 0, 0, 0},
805         {0xE3, 0, 0, 0, 0},
806         {0xE4, 0, 0, 0, 0},
807         {0xE5, 0xf5, 0xf5, 0, 0},
808         {0xE6, 0x30, 0x30, 0, 0},
809         {0xE7, 0x1, 0x1, 0, 0},
810         {0xE8, 0, 0, 0, 0},
811         {0xE9, 0xff, 0xff, 0, 0},
812         {0xEA, 0, 0, 0, 0},
813         {0xEB, 0, 0, 0, 0},
814         {0xEC, 0x22, 0x22, 0, 0},
815         {0xED, 0, 0, 0, 0},
816         {0xEE, 0, 0, 0, 0},
817         {0xEF, 0, 0, 0, 0},
818         {0xF0, 0x3, 0x3, 0, 0},
819         {0xF1, 0x1, 0x1, 0, 0},
820         {0xF2, 0, 0, 0, 0},
821         {0xF3, 0, 0, 0, 0},
822         {0xF4, 0, 0, 0, 0},
823         {0xF5, 0, 0, 0, 0},
824         {0xF6, 0, 0, 0, 0},
825         {0xF7, 0x6, 0x6, 0, 0},
826         {0xF8, 0, 0, 0, 0},
827         {0xF9, 0, 0, 0, 0},
828         {0xFA, 0x40, 0x40, 0, 0},
829         {0xFB, 0, 0, 0, 0},
830         {0xFC, 0x1, 0x1, 0, 0},
831         {0xFD, 0x80, 0x80, 0, 0},
832         {0xFE, 0x2, 0x2, 0, 0},
833         {0xFF, 0x10, 0x10, 0, 0},
834         {0x100, 0x2, 0x2, 0, 0},
835         {0x101, 0x1e, 0x1e, 0, 0},
836         {0x102, 0x1e, 0x1e, 0, 0},
837         {0x103, 0, 0, 0, 0},
838         {0x104, 0x1f, 0x1f, 0, 0},
839         {0x105, 0, 0x8, 0, 1},
840         {0x106, 0x2a, 0x2a, 0, 0},
841         {0x107, 0xf, 0xf, 0, 0},
842         {0x108, 0, 0, 0, 0},
843         {0x109, 0, 0, 0, 0},
844         {0x10A, 0, 0, 0, 0},
845         {0x10B, 0, 0, 0, 0},
846         {0x10C, 0, 0, 0, 0},
847         {0x10D, 0, 0, 0, 0},
848         {0x10E, 0, 0, 0, 0},
849         {0x10F, 0, 0, 0, 0},
850         {0x110, 0, 0, 0, 0},
851         {0x111, 0, 0, 0, 0},
852         {0x112, 0, 0, 0, 0},
853         {0x113, 0, 0, 0, 0},
854         {0x114, 0, 0, 0, 0},
855         {0x115, 0, 0, 0, 0},
856         {0x116, 0, 0, 0, 0},
857         {0x117, 0, 0, 0, 0},
858         {0x118, 0, 0, 0, 0},
859         {0x119, 0, 0, 0, 0},
860         {0x11A, 0, 0, 0, 0},
861         {0x11B, 0, 0, 0, 0},
862         {0x11C, 0x1, 0x1, 0, 0},
863         {0x11D, 0, 0, 0, 0},
864         {0x11E, 0, 0, 0, 0},
865         {0x11F, 0, 0, 0, 0},
866         {0x120, 0, 0, 0, 0},
867         {0x121, 0, 0, 0, 0},
868         {0x122, 0x80, 0x80, 0, 0},
869         {0x123, 0, 0, 0, 0},
870         {0x124, 0xf8, 0xf8, 0, 0},
871         {0x125, 0, 0, 0, 0},
872         {0x126, 0, 0, 0, 0},
873         {0x127, 0, 0, 0, 0},
874         {0x128, 0, 0, 0, 0},
875         {0x129, 0, 0, 0, 0},
876         {0x12A, 0, 0, 0, 0},
877         {0x12B, 0, 0, 0, 0},
878         {0x12C, 0, 0, 0, 0},
879         {0x12D, 0, 0, 0, 0},
880         {0x12E, 0, 0, 0, 0},
881         {0x12F, 0, 0, 0, 0},
882         {0x130, 0, 0, 0, 0},
883         {0xFFFF, 0, 0, 0, 0}
884 };
885
886 #define LCNPHY_NUM_DIG_FILT_COEFFS 16
887 #define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
888
889 static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
890         [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
891         {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
892          128, 64,},
893         {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
894          167, 93,},
895         {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
896          128, 64,},
897         {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
898          170, 340, 170,},
899         {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
900          256, 185, 256,},
901         {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
902          256, 273, 256,},
903         {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
904          256, 352, 256,},
905         {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
906          128, 233, 128,},
907         {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
908          1881, 256,},
909         {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
910          1881, 256,},
911         {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
912          384, 288,},
913         {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
914          128, 384, 288,},
915         {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
916          170, 340, 170,},
917 };
918
919 #define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
920 static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
921         [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
922         {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
923          0x278, 0xfea0, 0x80, 0x100, 0x80,},
924         {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
925          750, 0xFE2B, 212, 0xFFCE, 212,},
926         {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
927          0xFEF2, 128, 0xFFE2, 128}
928 };
929
930 #define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
931         mod_phy_reg(pi, 0x4a4, \
932                     (0x1ff << 0), \
933                     (u16)(idx) << 0)
934
935 #define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
936         mod_phy_reg(pi, 0x4a5, \
937                     (0x7 << 8), \
938                     (u16)(npt) << 8)
939
940 #define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
941         (read_phy_reg((pi), 0x4a4) & \
942          ((0x1 << 15) | \
943           (0x1 << 14) | \
944           (0x1 << 13)))
945
946 #define wlc_lcnphy_get_tx_pwr_npt(pi) \
947         ((read_phy_reg(pi, 0x4a5) & \
948           (0x7 << 8)) >> \
949          8)
950
951 #define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
952         (read_phy_reg(pi, 0x473) & 0x1ff)
953
954 #define wlc_lcnphy_get_target_tx_pwr(pi) \
955         ((read_phy_reg(pi, 0x4a7) & \
956           (0xff << 0)) >> \
957          0)
958
959 #define wlc_lcnphy_set_target_tx_pwr(pi, target) \
960         mod_phy_reg(pi, 0x4a7, \
961                     (0xff << 0), \
962                     (u16)(target) << 0)
963
964 #define wlc_radio_2064_rcal_done(pi) \
965         (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
966
967 #define tempsense_done(pi) \
968         (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
969
970 #define LCNPHY_IQLOCC_READ(val) \
971         ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
972
973 #define FIXED_TXPWR 78
974 #define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val))
975
976 void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti)
977 {
978         wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
979 }
980
981 void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti)
982 {
983         wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
984 }
985
986 static void
987 wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id,
988                              const u16 *tbl_ptr, u32 tbl_len,
989                              u32 tbl_width, u32 tbl_offset)
990 {
991         struct phytbl_info tab;
992         tab.tbl_id = tbl_id;
993         tab.tbl_ptr = tbl_ptr;
994         tab.tbl_len = tbl_len;
995         tab.tbl_width = tbl_width;
996         tab.tbl_offset = tbl_offset;
997         wlc_lcnphy_read_table(pi, &tab);
998 }
999
1000 static void
1001 wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id,
1002                               const u16 *tbl_ptr, u32 tbl_len,
1003                               u32 tbl_width, u32 tbl_offset)
1004 {
1005
1006         struct phytbl_info tab;
1007         tab.tbl_id = tbl_id;
1008         tab.tbl_ptr = tbl_ptr;
1009         tab.tbl_len = tbl_len;
1010         tab.tbl_width = tbl_width;
1011         tab.tbl_offset = tbl_offset;
1012         wlc_lcnphy_write_table(pi, &tab);
1013 }
1014
1015 static u32
1016 wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
1017 {
1018         u32 quotient, remainder, roundup, rbit;
1019
1020         quotient = dividend / divisor;
1021         remainder = dividend % divisor;
1022         rbit = divisor & 1;
1023         roundup = (divisor >> 1) + rbit;
1024
1025         while (precision--) {
1026                 quotient <<= 1;
1027                 if (remainder >= roundup) {
1028                         quotient++;
1029                         remainder = ((remainder - roundup) << 1) + rbit;
1030                 } else {
1031                         remainder <<= 1;
1032                 }
1033         }
1034
1035         if (remainder >= roundup)
1036                 quotient++;
1037
1038         return quotient;
1039 }
1040
1041 static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
1042 {
1043         int k;
1044         k = 0;
1045         if (type == 0) {
1046                 if (coeff_x < 0)
1047                         k = (coeff_x - 1) / 2;
1048                 else
1049                         k = coeff_x / 2;
1050         }
1051
1052         if (type == 1) {
1053                 if ((coeff_x + 1) < 0)
1054                         k = (coeff_x) / 2;
1055                 else
1056                         k = (coeff_x + 1) / 2;
1057         }
1058         return k;
1059 }
1060
1061 static void
1062 wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains)
1063 {
1064         u16 dac_gain, rfgain0, rfgain1;
1065
1066         dac_gain = read_phy_reg(pi, 0x439) >> 0;
1067         gains->dac_gain = (dac_gain & 0x380) >> 7;
1068
1069         rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
1070         rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
1071
1072         gains->gm_gain = rfgain0 & 0xff;
1073         gains->pga_gain = (rfgain0 >> 8) & 0xff;
1074         gains->pad_gain = rfgain1 & 0xff;
1075 }
1076
1077
1078 static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain)
1079 {
1080         u16 dac_ctrl;
1081
1082         dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
1083         dac_ctrl = dac_ctrl & 0xc7f;
1084         dac_ctrl = dac_ctrl | (dac_gain << 7);
1085         mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
1086
1087 }
1088
1089 static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable)
1090 {
1091         u16 bit = bEnable ? 1 : 0;
1092
1093         mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
1094
1095         mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
1096
1097         mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
1098 }
1099
1100 static void
1101 wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable)
1102 {
1103         u16 ebit = enable ? 1 : 0;
1104
1105         mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
1106
1107         mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
1108
1109         if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
1110                 mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
1111                 mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
1112                 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
1113                 mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
1114         } else {
1115                 mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
1116                 mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
1117                 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
1118         }
1119
1120         if (CHSPEC_IS2G(pi->radio_chanspec)) {
1121                 mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
1122                 mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
1123         }
1124 }
1125
1126 static void
1127 wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
1128                                        u16 trsw,
1129                                        u16 ext_lna,
1130                                        u16 biq2,
1131                                        u16 biq1,
1132                                        u16 tia, u16 lna2, u16 lna1)
1133 {
1134         u16 gain0_15, gain16_19;
1135
1136         gain16_19 = biq2 & 0xf;
1137         gain0_15 = ((biq1 & 0xf) << 12) |
1138                    ((tia & 0xf) << 8) |
1139                    ((lna2 & 0x3) << 6) |
1140                    ((lna2 & 0x3) << 4) |
1141                    ((lna1 & 0x3) << 2) |
1142                    ((lna1 & 0x3) << 0);
1143
1144         mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
1145         mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
1146         mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
1147
1148         if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
1149                 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
1150                 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
1151         } else {
1152                 mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
1153
1154                 mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
1155
1156                 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
1157         }
1158
1159         mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
1160         mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
1161         mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
1162
1163 }
1164
1165 static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx)
1166 {
1167
1168         mod_phy_reg(pi, 0x44d,
1169                     (0x1 << 1) |
1170                     (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
1171
1172         or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
1173 }
1174
1175 static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi)
1176 {
1177
1178         and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
1179 }
1180
1181 static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b)
1182 {
1183         mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
1184
1185         mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
1186
1187         mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
1188
1189         mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
1190
1191         mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
1192
1193         mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
1194
1195 }
1196
1197 static bool
1198 wlc_lcnphy_rx_iq_est(struct brcms_phy *pi,
1199                      u16 num_samps,
1200                      u8 wait_time, struct lcnphy_iq_est *iq_est)
1201 {
1202         int wait_count = 0;
1203         bool result = true;
1204         u8 phybw40;
1205         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
1206
1207         mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
1208
1209         mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
1210
1211         mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
1212
1213         mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
1214
1215         mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
1216
1217         mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
1218
1219         while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
1220
1221                 if (wait_count > (10 * 500)) {
1222                         result = false;
1223                         goto cleanup;
1224                 }
1225                 udelay(100);
1226                 wait_count++;
1227         }
1228
1229         iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |
1230                           (u32) read_phy_reg(pi, 0x484);
1231         iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |
1232                         (u32) read_phy_reg(pi, 0x486);
1233         iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |
1234                         (u32) read_phy_reg(pi, 0x488);
1235
1236 cleanup:
1237         mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
1238
1239         mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
1240
1241         return result;
1242 }
1243
1244 static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps)
1245 {
1246 #define LCNPHY_MIN_RXIQ_PWR 2
1247         bool result;
1248         u16 a0_new, b0_new;
1249         struct lcnphy_iq_est iq_est = { 0, 0, 0 };
1250         s32 a, b, temp;
1251         s16 iq_nbits, qq_nbits, arsh, brsh;
1252         s32 iq;
1253         u32 ii, qq;
1254         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1255
1256         a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
1257         b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
1258         mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
1259
1260         mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
1261
1262         wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
1263
1264         result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
1265         if (!result)
1266                 goto cleanup;
1267
1268         iq = (s32) iq_est.iq_prod;
1269         ii = iq_est.i_pwr;
1270         qq = iq_est.q_pwr;
1271
1272         if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
1273                 result = false;
1274                 goto cleanup;
1275         }
1276
1277         iq_nbits = wlc_phy_nbits(iq);
1278         qq_nbits = wlc_phy_nbits(qq);
1279
1280         arsh = 10 - (30 - iq_nbits);
1281         if (arsh >= 0) {
1282                 a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
1283                 temp = (s32) (ii >> arsh);
1284                 if (temp == 0)
1285                         return false;
1286         } else {
1287                 a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
1288                 temp = (s32) (ii << -arsh);
1289                 if (temp == 0)
1290                         return false;
1291         }
1292         a /= temp;
1293         brsh = qq_nbits - 31 + 20;
1294         if (brsh >= 0) {
1295                 b = (qq << (31 - qq_nbits));
1296                 temp = (s32) (ii >> brsh);
1297                 if (temp == 0)
1298                         return false;
1299         } else {
1300                 b = (qq << (31 - qq_nbits));
1301                 temp = (s32) (ii << -brsh);
1302                 if (temp == 0)
1303                         return false;
1304         }
1305         b /= temp;
1306         b -= a * a;
1307         b = (s32) int_sqrt((unsigned long) b);
1308         b -= (1 << 10);
1309         a0_new = (u16) (a & 0x3ff);
1310         b0_new = (u16) (b & 0x3ff);
1311 cleanup:
1312
1313         wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
1314
1315         mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
1316
1317         mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
1318
1319         pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
1320         pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
1321
1322         return result;
1323 }
1324
1325 static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
1326 {
1327         struct lcnphy_iq_est iq_est = { 0, 0, 0 };
1328
1329         if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))
1330                 return 0;
1331         return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
1332 }
1333
1334 static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,
1335                                       u16 tia_gain, u16 lna2_gain)
1336 {
1337         u32 i_thresh_l, q_thresh_l;
1338         u32 i_thresh_h, q_thresh_h;
1339         struct lcnphy_iq_est iq_est_h, iq_est_l;
1340
1341         wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain,
1342                                                lna2_gain, 0);
1343
1344         wlc_lcnphy_rx_gain_override_enable(pi, true);
1345         wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);
1346         udelay(500);
1347         write_radio_reg(pi, RADIO_2064_REG112, 0);
1348         if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))
1349                 return false;
1350
1351         wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);
1352         udelay(500);
1353         write_radio_reg(pi, RADIO_2064_REG112, 0);
1354         if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))
1355                 return false;
1356
1357         i_thresh_l = (iq_est_l.i_pwr << 1);
1358         i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr;
1359
1360         q_thresh_l = (iq_est_l.q_pwr << 1);
1361         q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr;
1362         if ((iq_est_h.i_pwr > i_thresh_l) &&
1363             (iq_est_h.i_pwr < i_thresh_h) &&
1364             (iq_est_h.q_pwr > q_thresh_l) &&
1365             (iq_est_h.q_pwr < q_thresh_h))
1366                 return true;
1367
1368         return false;
1369 }
1370
1371 static bool
1372 wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
1373                      const struct lcnphy_rx_iqcomp *iqcomp,
1374                      int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
1375                      int tx_gain_idx)
1376 {
1377         struct lcnphy_txgains old_gains;
1378         u16 tx_pwr_ctrl;
1379         u8 tx_gain_index_old = 0;
1380         bool result = false, tx_gain_override_old = false;
1381         u16 i, Core1TxControl_old, RFOverride0_old,
1382             RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
1383             rfoverride3_old, rfoverride3val_old, rfoverride4_old,
1384             rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
1385         int tia_gain, lna2_gain, biq1_gain;
1386         bool set_gain;
1387         u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
1388         u16 values_to_save[11];
1389         s16 *ptr;
1390         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1391
1392         ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
1393         if (NULL == ptr)
1394                 return false;
1395         if (module == 2) {
1396                 while (iqcomp_sz--) {
1397                         if (iqcomp[iqcomp_sz].chan ==
1398                             CHSPEC_CHANNEL(pi->radio_chanspec)) {
1399                                 wlc_lcnphy_set_rx_iq_comp(pi,
1400                                                           (u16)
1401                                                           iqcomp[iqcomp_sz].a,
1402                                                           (u16)
1403                                                           iqcomp[iqcomp_sz].b);
1404                                 result = true;
1405                                 break;
1406                         }
1407                 }
1408                 goto cal_done;
1409         }
1410
1411         WARN_ON(module != 1);
1412         tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1413         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1414
1415         for (i = 0; i < 11; i++)
1416                 values_to_save[i] =
1417                         read_radio_reg(pi, rxiq_cal_rf_reg[i]);
1418         Core1TxControl_old = read_phy_reg(pi, 0x631);
1419
1420         or_phy_reg(pi, 0x631, 0x0015);
1421
1422         RFOverride0_old = read_phy_reg(pi, 0x44c);
1423         RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
1424         rfoverride2_old = read_phy_reg(pi, 0x4b0);
1425         rfoverride2val_old = read_phy_reg(pi, 0x4b1);
1426         rfoverride3_old = read_phy_reg(pi, 0x4f9);
1427         rfoverride3val_old = read_phy_reg(pi, 0x4fa);
1428         rfoverride4_old = read_phy_reg(pi, 0x938);
1429         rfoverride4val_old = read_phy_reg(pi, 0x939);
1430         afectrlovr_old = read_phy_reg(pi, 0x43b);
1431         afectrlovrval_old = read_phy_reg(pi, 0x43c);
1432         old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1433         old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1434
1435         tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1436         if (tx_gain_override_old) {
1437                 wlc_lcnphy_get_tx_gain(pi, &old_gains);
1438                 tx_gain_index_old = pi_lcn->lcnphy_current_index;
1439         }
1440
1441         wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
1442
1443         mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
1444         mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
1445
1446         mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
1447         mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
1448
1449         write_radio_reg(pi, RADIO_2064_REG116, 0x06);
1450         write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
1451         write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
1452         write_radio_reg(pi, RADIO_2064_REG098, 0x03);
1453         write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
1454         mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
1455         write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
1456         write_radio_reg(pi, RADIO_2064_REG114, 0x01);
1457         write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
1458         write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
1459
1460         mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
1461         mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
1462         mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
1463         mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
1464         mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
1465         mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
1466         mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
1467         mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
1468         mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
1469         mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
1470
1471         mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
1472         mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
1473
1474         write_phy_reg(pi, 0x6da, 0xffff);
1475         or_phy_reg(pi, 0x6db, 0x3);
1476
1477         wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
1478         set_gain = false;
1479
1480         lna2_gain = 3;
1481         while ((lna2_gain >= 0) && !set_gain) {
1482                 tia_gain = 4;
1483
1484                 while ((tia_gain >= 0) && !set_gain) {
1485                         biq1_gain = 6;
1486
1487                         while ((biq1_gain >= 0) && !set_gain) {
1488                                 set_gain = wlc_lcnphy_rx_iq_cal_gain(pi,
1489                                                                      (u16)
1490                                                                      biq1_gain,
1491                                                                      (u16)
1492                                                                      tia_gain,
1493                                                                      (u16)
1494                                                                      lna2_gain);
1495                                 biq1_gain -= 1;
1496                         }
1497                         tia_gain -= 1;
1498                 }
1499                 lna2_gain -= 1;
1500         }
1501
1502         if (set_gain)
1503                 result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024);
1504         else
1505                 result = false;
1506
1507         wlc_lcnphy_stop_tx_tone(pi);
1508
1509         write_phy_reg(pi, 0x631, Core1TxControl_old);
1510
1511         write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
1512         write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
1513         write_phy_reg(pi, 0x4b0, rfoverride2_old);
1514         write_phy_reg(pi, 0x4b1, rfoverride2val_old);
1515         write_phy_reg(pi, 0x4f9, rfoverride3_old);
1516         write_phy_reg(pi, 0x4fa, rfoverride3val_old);
1517         write_phy_reg(pi, 0x938, rfoverride4_old);
1518         write_phy_reg(pi, 0x939, rfoverride4val_old);
1519         write_phy_reg(pi, 0x43b, afectrlovr_old);
1520         write_phy_reg(pi, 0x43c, afectrlovrval_old);
1521         write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
1522         write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
1523
1524         wlc_lcnphy_clear_trsw_override(pi);
1525
1526         mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
1527
1528         for (i = 0; i < 11; i++)
1529                 write_radio_reg(pi, rxiq_cal_rf_reg[i],
1530                                 values_to_save[i]);
1531
1532         if (tx_gain_override_old)
1533                 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
1534         else
1535                 wlc_lcnphy_disable_tx_gain_override(pi);
1536
1537         wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
1538         wlc_lcnphy_rx_gain_override_enable(pi, false);
1539
1540 cal_done:
1541         kfree(ptr);
1542         return result;
1543 }
1544
1545 s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi)
1546 {
1547         s8 index;
1548         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1549
1550         if (txpwrctrl_off(pi))
1551                 index = pi_lcn->lcnphy_current_index;
1552         else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1553                 index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(
1554                               pi) / 2);
1555         else
1556                 index = pi_lcn->lcnphy_current_index;
1557         return index;
1558 }
1559
1560 void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel)
1561 {
1562         u16 afectrlovr, afectrlovrval;
1563         afectrlovr = read_phy_reg(pi, 0x43b);
1564         afectrlovrval = read_phy_reg(pi, 0x43c);
1565         if (channel != 0) {
1566                 mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
1567
1568                 mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1569
1570                 mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1571
1572                 mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1573
1574                 write_phy_reg(pi, 0x44b, 0xffff);
1575                 wlc_lcnphy_tx_pu(pi, 1);
1576
1577                 mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1578
1579                 or_phy_reg(pi, 0x6da, 0x0080);
1580
1581                 or_phy_reg(pi, 0x00a, 0x228);
1582         } else {
1583                 and_phy_reg(pi, 0x00a, ~(0x228));
1584
1585                 and_phy_reg(pi, 0x6da, 0xFF7F);
1586                 write_phy_reg(pi, 0x43b, afectrlovr);
1587                 write_phy_reg(pi, 0x43c, afectrlovrval);
1588         }
1589 }
1590
1591 static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi)
1592 {
1593         u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
1594
1595         save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1596         save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1597
1598         write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1599         write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1600
1601         write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1602         write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1603
1604         write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1605         write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1606 }
1607
1608 static void
1609 wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable)
1610 {
1611         if (enable) {
1612                 write_phy_reg(pi, 0x942, 0x7);
1613                 write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
1614                 write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
1615
1616                 write_phy_reg(pi, 0x44a, 0x084);
1617                 write_phy_reg(pi, 0x44a, 0x080);
1618                 write_phy_reg(pi, 0x6d3, 0x2222);
1619                 write_phy_reg(pi, 0x6d3, 0x2220);
1620         } else {
1621                 write_phy_reg(pi, 0x942, 0x0);
1622                 write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
1623                 write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
1624         }
1625         wlapi_switch_macfreq(pi->sh->physhim, enable);
1626 }
1627
1628 static void
1629 wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
1630 {
1631         u8 channel = CHSPEC_CHANNEL(chanspec);
1632         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1633
1634         if (channel == 14)
1635                 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1636         else
1637                 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1638
1639         pi_lcn->lcnphy_bandedge_corr = 2;
1640         if (channel == 1)
1641                 pi_lcn->lcnphy_bandedge_corr = 4;
1642
1643         if (channel == 1 || channel == 2 || channel == 3 ||
1644             channel == 4 || channel == 9 ||
1645             channel == 10 || channel == 11 || channel == 12) {
1646                 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
1647                 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
1648                 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
1649
1650                 si_pmu_pllupd(pi->sh->sih);
1651                 write_phy_reg(pi, 0x942, 0);
1652                 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
1653                 pi_lcn->lcnphy_spurmod = false;
1654                 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
1655
1656                 write_phy_reg(pi, 0x425, 0x5907);
1657         } else {
1658                 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
1659                 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
1660                 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
1661
1662                 si_pmu_pllupd(pi->sh->sih);
1663                 write_phy_reg(pi, 0x942, 0);
1664                 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
1665
1666                 pi_lcn->lcnphy_spurmod = false;
1667                 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
1668
1669                 write_phy_reg(pi, 0x425, 0x590a);
1670         }
1671
1672         or_phy_reg(pi, 0x44a, 0x44);
1673         write_phy_reg(pi, 0x44a, 0x80);
1674 }
1675
1676 static void
1677 wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
1678 {
1679         uint i;
1680         const struct chan_info_2064_lcnphy *ci;
1681         u8 rfpll_doubler = 0;
1682         u8 pll_pwrup, pll_pwrup_ovr;
1683         s32 qFxtal, qFref, qFvco, qFcal;
1684         u8 d15, d16, f16, e44, e45;
1685         u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
1686         u16 loop_bw, d30, setCount;
1687
1688         u8 h29, h28_ten, e30, h30_ten, cp_current;
1689         u16 g30, d28;
1690
1691         ci = &chan_info_2064_lcnphy[0];
1692         rfpll_doubler = 1;
1693
1694         mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
1695
1696         write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
1697         if (!rfpll_doubler) {
1698                 loop_bw = PLL_2064_LOOP_BW;
1699                 d30 = PLL_2064_D30;
1700         } else {
1701                 loop_bw = PLL_2064_LOOP_BW_DOUBLER;
1702                 d30 = PLL_2064_D30_DOUBLER;
1703         }
1704
1705         if (CHSPEC_IS2G(pi->radio_chanspec)) {
1706                 for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)
1707                         if (chan_info_2064_lcnphy[i].chan == channel)
1708                                 break;
1709
1710                 if (i >= ARRAY_SIZE(chan_info_2064_lcnphy))
1711                         return;
1712
1713                 ci = &chan_info_2064_lcnphy[i];
1714         }
1715
1716         write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
1717
1718         mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
1719
1720         mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
1721
1722         mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
1723
1724         mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
1725                       (ci->logen_rccr_rx) << 2);
1726
1727         mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
1728
1729         mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
1730                       (ci->pa_rxrf_lna2_freq_tune) << 4);
1731
1732         write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
1733
1734         pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
1735         pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
1736
1737         or_radio_reg(pi, RADIO_2064_REG044, 0x07);
1738
1739         or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
1740         e44 = 0;
1741         e45 = 0;
1742
1743         fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
1744         if (pi->xtalfreq > 26000000)
1745                 e44 = 1;
1746         if (pi->xtalfreq > 52000000)
1747                 e45 = 1;
1748         if (e44 == 0)
1749                 fcal_div = 1;
1750         else if (e45 == 0)
1751                 fcal_div = 2;
1752         else
1753                 fcal_div = 4;
1754         fvco3 = (ci->freq * 3);
1755         fref3 = 2 * fpfd;
1756
1757         qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
1758         qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
1759         qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
1760         qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
1761
1762         write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
1763
1764         d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
1765         write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
1766         write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
1767
1768         d16 = (qFcal * 8 / (d15 + 1)) - 1;
1769         write_radio_reg(pi, RADIO_2064_REG051, d16);
1770
1771         f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
1772         setCount = f16 * 3 * (ci->freq) / 32 - 1;
1773         mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
1774                       (u8) (setCount >> 8));
1775
1776         or_radio_reg(pi, RADIO_2064_REG053, 0x10);
1777         write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
1778
1779         div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
1780
1781         div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
1782         while (div_frac >= fref3) {
1783                 div_int++;
1784                 div_frac -= fref3;
1785         }
1786         div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
1787
1788         mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
1789                       (u8) (div_int >> 4));
1790         mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
1791                       (u8) (div_int << 4));
1792         mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
1793                       (u8) (div_frac >> 16));
1794         write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
1795         write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
1796
1797         write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
1798
1799         write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
1800         write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
1801         write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
1802
1803         h29 = LCN_BW_LMT / loop_bw;
1804         d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
1805                 (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
1806                (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
1807               + PLL_2064_LOW_END_KVCO;
1808         h28_ten = (d28 * 10) / LCN_VCO_DIV;
1809         e30 = (d30 - LCN_OFFSET) / LCN_FACT;
1810         g30 = LCN_OFFSET + (e30 * LCN_FACT);
1811         h30_ten = (g30 * 10) / LCN_CUR_DIV;
1812         cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten;
1813         mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
1814
1815         if (channel >= 1 && channel <= 5)
1816                 write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
1817         else
1818                 write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
1819         write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
1820
1821         mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
1822         udelay(1);
1823
1824         wlc_2064_vco_cal(pi);
1825
1826         write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
1827         write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
1828         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
1829                 write_radio_reg(pi, RADIO_2064_REG038, 3);
1830                 write_radio_reg(pi, RADIO_2064_REG091, 7);
1831         }
1832
1833         if (!(pi->sh->boardflags & BFL_FEM)) {
1834                 u8 reg038[14] = {0xd, 0xe, 0xd, 0xd, 0xd, 0xc,
1835                         0xa, 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0};
1836
1837                 write_radio_reg(pi, RADIO_2064_REG02A, 0xf);
1838                 write_radio_reg(pi, RADIO_2064_REG091, 0x3);
1839                 write_radio_reg(pi, RADIO_2064_REG038, 0x3);
1840
1841                 write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]);
1842         }
1843 }
1844
1845 static int
1846 wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type)
1847 {
1848         s16 filt_index = -1;
1849         int j;
1850
1851         u16 addr[] = {
1852                 0x910,
1853                 0x91e,
1854                 0x91f,
1855                 0x924,
1856                 0x925,
1857                 0x926,
1858                 0x920,
1859                 0x921,
1860                 0x927,
1861                 0x928,
1862                 0x929,
1863                 0x922,
1864                 0x923,
1865                 0x930,
1866                 0x931,
1867                 0x932
1868         };
1869
1870         u16 addr_ofdm[] = {
1871                 0x90f,
1872                 0x900,
1873                 0x901,
1874                 0x906,
1875                 0x907,
1876                 0x908,
1877                 0x902,
1878                 0x903,
1879                 0x909,
1880                 0x90a,
1881                 0x90b,
1882                 0x904,
1883                 0x905,
1884                 0x90c,
1885                 0x90d,
1886                 0x90e
1887         };
1888
1889         if (!is_ofdm) {
1890                 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
1891                         if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
1892                                 filt_index = (s16) j;
1893                                 break;
1894                         }
1895                 }
1896
1897                 if (filt_index != -1) {
1898                         for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1899                                 write_phy_reg(pi, addr[j],
1900                                               LCNPHY_txdigfiltcoeffs_cck
1901                                               [filt_index][j + 1]);
1902                 }
1903         } else {
1904                 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
1905                         if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
1906                                 filt_index = (s16) j;
1907                                 break;
1908                         }
1909                 }
1910
1911                 if (filt_index != -1) {
1912                         for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1913                                 write_phy_reg(pi, addr_ofdm[j],
1914                                               LCNPHY_txdigfiltcoeffs_ofdm
1915                                               [filt_index][j + 1]);
1916                 }
1917         }
1918
1919         return (filt_index != -1) ? 0 : -1;
1920 }
1921
1922 static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi)
1923 {
1924         u16 pa_gain;
1925
1926         pa_gain = (read_phy_reg(pi, 0x4fb) &
1927                    LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1928                   LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1929
1930         return pa_gain;
1931 }
1932
1933 static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,
1934                                    struct lcnphy_txgains *target_gains)
1935 {
1936         u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1937
1938         mod_phy_reg(
1939                 pi, 0x4b5,
1940                 (0xffff << 0),
1941                 ((target_gains->gm_gain) |
1942                  (target_gains->pga_gain << 8)) <<
1943                 0);
1944         mod_phy_reg(pi, 0x4fb,
1945                     (0x7fff << 0),
1946                     ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1947
1948         mod_phy_reg(
1949                 pi, 0x4fc,
1950                 (0xffff << 0),
1951                 ((target_gains->gm_gain) |
1952                  (target_gains->pga_gain << 8)) <<
1953                 0);
1954         mod_phy_reg(pi, 0x4fd,
1955                     (0x7fff << 0),
1956                     ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1957
1958         wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1959
1960         wlc_lcnphy_enable_tx_gain_override(pi);
1961 }
1962
1963 static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi)
1964 {
1965         u16 m0m1;
1966         struct phytbl_info tab;
1967
1968         tab.tbl_ptr = &m0m1;
1969         tab.tbl_len = 1;
1970         tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1971         tab.tbl_offset = 87;
1972         tab.tbl_width = 16;
1973         wlc_lcnphy_read_table(pi, &tab);
1974
1975         return (u8) ((m0m1 & 0xff00) >> 8);
1976 }
1977
1978 static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0)
1979 {
1980         u16 m0m1 = (u16) m0 << 8;
1981         struct phytbl_info tab;
1982
1983         tab.tbl_ptr = &m0m1;
1984         tab.tbl_len = 1;
1985         tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1986         tab.tbl_offset = 87;
1987         tab.tbl_width = 16;
1988         wlc_lcnphy_write_table(pi, &tab);
1989 }
1990
1991 static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi)
1992 {
1993         u32 data_buf[64];
1994         struct phytbl_info tab;
1995
1996         memset(data_buf, 0, sizeof(data_buf));
1997
1998         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1999         tab.tbl_width = 32;
2000         tab.tbl_ptr = data_buf;
2001
2002         if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
2003
2004                 tab.tbl_len = 30;
2005                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2006                 wlc_lcnphy_write_table(pi, &tab);
2007         }
2008
2009         tab.tbl_len = 64;
2010         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
2011         wlc_lcnphy_write_table(pi, &tab);
2012 }
2013
2014 enum lcnphy_tssi_mode {
2015         LCNPHY_TSSI_PRE_PA,
2016         LCNPHY_TSSI_POST_PA,
2017         LCNPHY_TSSI_EXT
2018 };
2019
2020 static void
2021 wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
2022 {
2023         mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
2024
2025         mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
2026
2027         if (LCNPHY_TSSI_POST_PA == pos) {
2028                 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
2029
2030                 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
2031
2032                 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2033                         mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2034                 } else {
2035                         mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
2036                         mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2037                         mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0);
2038                         mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2);
2039                         mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0);
2040                         mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4);
2041                         mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
2042                         mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77);
2043                         mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1);
2044                         mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7);
2045                         mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1);
2046                         mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4);
2047                 }
2048         } else {
2049                 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
2050
2051                 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
2052
2053                 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2054                         mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2055                 } else {
2056                         mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2057                         mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2058                 }
2059         }
2060         mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
2061
2062         if (LCNPHY_TSSI_EXT == pos) {
2063                 write_radio_reg(pi, RADIO_2064_REG07F, 1);
2064                 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
2065                 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
2066                 mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
2067         }
2068 }
2069
2070 static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi)
2071 {
2072         u16 N1, N2, N3, N4, N5, N6, N;
2073         N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
2074               >> 0);
2075         N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
2076                    >> 12);
2077         N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
2078               >> 0);
2079         N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
2080                    >> 8);
2081         N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
2082               >> 0);
2083         N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
2084                    >> 8);
2085         N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
2086         if (N < 1600)
2087                 N = 1600;
2088         return N;
2089 }
2090
2091 static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
2092 {
2093         u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
2094         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2095
2096         auxpga_vmid = (2 << 8) |
2097                       (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
2098         auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
2099         auxpga_gain_temp = 2;
2100
2101         mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
2102
2103         mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
2104
2105         mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
2106
2107         mod_phy_reg(pi, 0x4db,
2108                     (0x3ff << 0) |
2109                     (0x7 << 12),
2110                     (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2111
2112         mod_phy_reg(pi, 0x4dc,
2113                     (0x3ff << 0) |
2114                     (0x7 << 12),
2115                     (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2116
2117         mod_phy_reg(pi, 0x40a,
2118                     (0x3ff << 0) |
2119                     (0x7 << 12),
2120                     (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2121
2122         mod_phy_reg(pi, 0x40b,
2123                     (0x3ff << 0) |
2124                     (0x7 << 12),
2125                     (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2126
2127         mod_phy_reg(pi, 0x40c,
2128                     (0x3ff << 0) |
2129                     (0x7 << 12),
2130                     (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2131
2132         mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
2133         mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0));
2134 }
2135
2136 static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
2137 {
2138         struct phytbl_info tab;
2139         u32 rfseq, ind;
2140         u8 tssi_sel;
2141
2142         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2143         tab.tbl_width = 32;
2144         tab.tbl_ptr = &ind;
2145         tab.tbl_len = 1;
2146         tab.tbl_offset = 0;
2147         for (ind = 0; ind < 128; ind++) {
2148                 wlc_lcnphy_write_table(pi, &tab);
2149                 tab.tbl_offset++;
2150         }
2151         tab.tbl_offset = 704;
2152         for (ind = 0; ind < 128; ind++) {
2153                 wlc_lcnphy_write_table(pi, &tab);
2154                 tab.tbl_offset++;
2155         }
2156         mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2157
2158         mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2159
2160         mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
2161
2162         if (pi->sh->boardflags & BFL_FEM) {
2163                 tssi_sel = 0x1;
2164                 wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
2165         } else {
2166                 tssi_sel = 0xe;
2167                 wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_POST_PA);
2168         }
2169         mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2170
2171         mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
2172
2173         mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2174
2175         mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
2176
2177         mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2178
2179         mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2180
2181         mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2182
2183         mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2184
2185         mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
2186
2187         mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2188
2189         mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
2190
2191         mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
2192
2193         mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
2194
2195         wlc_lcnphy_clear_tx_power_offsets(pi);
2196
2197         mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2198
2199         mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
2200
2201         mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
2202
2203         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2204                 mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel);
2205                 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2206         } else {
2207                 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1);
2208                 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2209                 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
2210         }
2211
2212         write_radio_reg(pi, RADIO_2064_REG025, 0xc);
2213
2214         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2215                 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2216         } else {
2217                 if (CHSPEC_IS2G(pi->radio_chanspec))
2218                         mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2219                 else
2220                         mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
2221         }
2222
2223         if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2224                 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2225         else
2226                 mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
2227
2228         mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
2229
2230         mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
2231
2232         if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2233                 mod_phy_reg(pi, 0x4d7,
2234                             (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
2235
2236         rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2237         tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2238         tab.tbl_width = 16;
2239         tab.tbl_ptr = &rfseq;
2240         tab.tbl_len = 1;
2241         tab.tbl_offset = 6;
2242         wlc_lcnphy_write_table(pi, &tab);
2243
2244         mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2245
2246         mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2247
2248         mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2249
2250         mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
2251
2252         mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
2253
2254         mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0);
2255         mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
2256         mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2257
2258         wlc_lcnphy_pwrctrl_rssiparams(pi);
2259 }
2260
2261 void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi)
2262 {
2263         u16 tx_cnt, tx_total, npt;
2264         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2265
2266         tx_total = wlc_lcnphy_total_tx_frames(pi);
2267         tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
2268         npt = wlc_lcnphy_get_tx_pwr_npt(pi);
2269
2270         if (tx_cnt > (1 << npt)) {
2271
2272                 pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
2273
2274                 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2275                 pi_lcn->lcnphy_tssi_npt = npt;
2276
2277         }
2278 }
2279
2280 s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)
2281 {
2282         s32 a, b, p;
2283
2284         a = 32768 + (a1 * tssi);
2285         b = (1024 * b0) + (64 * b1 * tssi);
2286         p = ((2 * b) + a) / (2 * a);
2287
2288         return p;
2289 }
2290
2291 static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi)
2292 {
2293         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2294         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2295                 return;
2296
2297         pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
2298         pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
2299 }
2300
2301 void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi)
2302 {
2303         struct phytbl_info tab;
2304         u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM +
2305                        BRCMS_NUM_RATES_MCS_1_STREAM];
2306         uint i, j;
2307         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2308                 return;
2309
2310         for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {
2311
2312                 if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM)
2313                         j = TXP_FIRST_MCS_20_SISO;
2314
2315                 rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));
2316         }
2317
2318         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2319         tab.tbl_width = 32;
2320         tab.tbl_len = ARRAY_SIZE(rate_table);
2321         tab.tbl_ptr = rate_table;
2322         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2323         wlc_lcnphy_write_table(pi, &tab);
2324
2325         if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
2326                 wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
2327
2328                 wlc_lcnphy_txpower_reset_npt(pi);
2329         }
2330 }
2331
2332 static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index)
2333 {
2334         u32 cck_offset[4] = { 22, 22, 22, 22 };
2335         u32 ofdm_offset, reg_offset_cck;
2336         int i;
2337         u16 index2;
2338         struct phytbl_info tab;
2339
2340         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2341                 return;
2342
2343         mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2344
2345         mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
2346
2347         or_phy_reg(pi, 0x6da, 0x0040);
2348
2349         reg_offset_cck = 0;
2350         for (i = 0; i < 4; i++)
2351                 cck_offset[i] -= reg_offset_cck;
2352         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2353         tab.tbl_width = 32;
2354         tab.tbl_len = 4;
2355         tab.tbl_ptr = cck_offset;
2356         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2357         wlc_lcnphy_write_table(pi, &tab);
2358         ofdm_offset = 0;
2359         tab.tbl_len = 1;
2360         tab.tbl_ptr = &ofdm_offset;
2361         for (i = 836; i < 862; i++) {
2362                 tab.tbl_offset = i;
2363                 wlc_lcnphy_write_table(pi, &tab);
2364         }
2365
2366         mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
2367
2368         mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2369
2370         mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
2371
2372         mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
2373
2374         mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
2375
2376         mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
2377
2378         index2 = (u16) (index * 2);
2379         mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
2380
2381         mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
2382
2383 }
2384
2385 static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)
2386 {
2387         s8 index, delta_brd, delta_temp, new_index, tempcorrx;
2388         s16 manp, meas_temp, temp_diff;
2389         bool neg = false;
2390         u16 temp;
2391         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2392
2393         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2394                 return pi_lcn->lcnphy_current_index;
2395
2396         index = FIXED_TXPWR;
2397
2398         if (pi_lcn->lcnphy_tempsense_slope == 0)
2399                 return index;
2400
2401         temp = (u16) wlc_lcnphy_tempsense(pi, 0);
2402         meas_temp = LCNPHY_TEMPSENSE(temp);
2403
2404         if (pi->tx_power_min != 0)
2405                 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
2406         else
2407                 delta_brd = 0;
2408
2409         manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
2410         temp_diff = manp - meas_temp;
2411         if (temp_diff < 0) {
2412                 neg = true;
2413                 temp_diff = -temp_diff;
2414         }
2415
2416         delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
2417                                                   (u32) (pi_lcn->
2418                                                          lcnphy_tempsense_slope
2419                                                          * 10), 0);
2420         if (neg)
2421                 delta_temp = -delta_temp;
2422
2423         if (pi_lcn->lcnphy_tempsense_option == 3
2424             && LCNREV_IS(pi->pubpi.phy_rev, 0))
2425                 delta_temp = 0;
2426         if (pi_lcn->lcnphy_tempcorrx > 31)
2427                 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
2428         else
2429                 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
2430         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2431                 tempcorrx = 4;
2432         new_index =
2433                 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
2434         new_index += tempcorrx;
2435
2436         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2437                 index = 127;
2438
2439         if (new_index < 0 || new_index > 126)
2440                 return index;
2441
2442         return new_index;
2443 }
2444
2445 static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode)
2446 {
2447
2448         u16 current_mode = mode;
2449         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
2450             mode == LCNPHY_TX_PWR_CTRL_HW)
2451                 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
2452         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
2453             mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
2454                 current_mode = LCNPHY_TX_PWR_CTRL_HW;
2455         return current_mode;
2456 }
2457
2458 void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)
2459 {
2460         u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2461         s8 index;
2462         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2463
2464         mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
2465         old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
2466
2467         mod_phy_reg(pi, 0x6da, (0x1 << 6),
2468                     ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
2469
2470         mod_phy_reg(pi, 0x6a3, (0x1 << 4),
2471                     ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
2472
2473         if (old_mode != mode) {
2474                 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
2475
2476                         wlc_lcnphy_tx_pwr_update_npt(pi);
2477
2478                         wlc_lcnphy_clear_tx_power_offsets(pi);
2479                 }
2480                 if (LCNPHY_TX_PWR_CTRL_HW == mode) {
2481
2482                         wlc_lcnphy_txpower_recalc_target(pi);
2483
2484                         wlc_lcnphy_set_start_tx_pwr_idx(pi,
2485                                                         pi_lcn->
2486                                                         lcnphy_tssi_idx);
2487                         wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
2488                         mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
2489
2490                         pi_lcn->lcnphy_tssi_tx_cnt =
2491                                 wlc_lcnphy_total_tx_frames(pi);
2492
2493                         wlc_lcnphy_disable_tx_gain_override(pi);
2494                         pi_lcn->lcnphy_tx_power_idx_override = -1;
2495                 } else
2496                         wlc_lcnphy_enable_tx_gain_override(pi);
2497
2498                 mod_phy_reg(pi, 0x4a4,
2499                             ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
2500                 if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
2501                         index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
2502                         wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
2503                         pi_lcn->lcnphy_current_index = (s8)
2504                                                        ((read_phy_reg(pi,
2505                                                                       0x4a9) &
2506                                                          0xFF) / 2);
2507                 }
2508         }
2509 }
2510
2511 static void
2512 wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)
2513 {
2514         u16 vmid;
2515         int i;
2516         for (i = 0; i < 20; i++)
2517                 values_to_save[i] =
2518                         read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
2519
2520         mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2521         mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2522
2523         mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
2524         mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
2525
2526         mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2527         mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2528
2529         mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
2530         mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
2531
2532         if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2533                 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
2534         else
2535                 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
2536         or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
2537
2538         or_radio_reg(pi, RADIO_2064_REG036, 0x01);
2539         or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
2540         udelay(20);
2541
2542         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2543                 if (CHSPEC_IS5G(pi->radio_chanspec))
2544                         mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2545                 else
2546                         or_radio_reg(pi, RADIO_2064_REG03A, 1);
2547         } else {
2548                 if (CHSPEC_IS5G(pi->radio_chanspec))
2549                         mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
2550                 else
2551                         or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
2552         }
2553
2554         udelay(20);
2555
2556         write_radio_reg(pi, RADIO_2064_REG025, 0xF);
2557         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2558                 if (CHSPEC_IS5G(pi->radio_chanspec))
2559                         mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
2560                 else
2561                         mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
2562         } else {
2563                 if (CHSPEC_IS5G(pi->radio_chanspec))
2564                         mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
2565                 else
2566                         mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
2567         }
2568
2569         udelay(20);
2570
2571         write_radio_reg(pi, RADIO_2064_REG005, 0x8);
2572         or_radio_reg(pi, RADIO_2064_REG112, 0x80);
2573         udelay(20);
2574
2575         or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2576         or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2577         udelay(20);
2578
2579         or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
2580         or_radio_reg(pi, RADIO_2064_REG113, 0x10);
2581         udelay(20);
2582
2583         write_radio_reg(pi, RADIO_2064_REG007, 0x1);
2584         udelay(20);
2585
2586         vmid = 0x2A6;
2587         mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
2588         write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
2589         or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2590         udelay(20);
2591
2592         or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2593         udelay(20);
2594         write_radio_reg(pi, RADIO_2064_REG012, 0x02);
2595         or_radio_reg(pi, RADIO_2064_REG112, 0x06);
2596         write_radio_reg(pi, RADIO_2064_REG036, 0x11);
2597         write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
2598         write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
2599         write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
2600         write_radio_reg(pi, RADIO_2064_REG092, 0x15);
2601 }
2602
2603 static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)
2604 {
2605         uint delay_count = 0;
2606
2607         while (wlc_lcnphy_iqcal_active(pi)) {
2608                 udelay(100);
2609                 delay_count++;
2610
2611                 if (delay_count > (10 * 500))
2612                         break;
2613         }
2614
2615         return (0 == wlc_lcnphy_iqcal_active(pi));
2616 }
2617
2618 static void
2619 wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)
2620 {
2621         int i;
2622
2623         and_phy_reg(pi, 0x44c, 0x0 >> 11);
2624
2625         and_phy_reg(pi, 0x43b, 0xC);
2626
2627         for (i = 0; i < 20; i++)
2628                 write_radio_reg(pi, iqlo_loopback_rf_regs[i],
2629                                 values_to_save[i]);
2630 }
2631
2632 static void
2633 wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
2634                        struct lcnphy_txgains *target_gains,
2635                        enum lcnphy_cal_mode cal_mode, bool keep_tone)
2636 {
2637
2638         struct lcnphy_txgains cal_gains, temp_gains;
2639         u16 hash;
2640         u8 band_idx;
2641         int j;
2642         u16 ncorr_override[5];
2643         u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
2644                               0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
2645
2646         u16 commands_fullcal[] = {
2647                 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2648         };
2649
2650         u16 commands_recal[] = {
2651                 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2652         };
2653
2654         u16 command_nums_fullcal[] = {
2655                 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2656         };
2657
2658         u16 command_nums_recal[] = {
2659                 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2660         };
2661         u16 *command_nums = command_nums_fullcal;
2662
2663         u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
2664         u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
2665         u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
2666         bool tx_gain_override_old;
2667         struct lcnphy_txgains old_gains;
2668         uint i, n_cal_cmds = 0, n_cal_start = 0;
2669         u16 *values_to_save;
2670         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2671
2672         values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
2673         if (NULL == values_to_save)
2674                 return;
2675
2676         save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
2677         save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
2678
2679         or_phy_reg(pi, 0x6da, 0x40);
2680         or_phy_reg(pi, 0x6db, 0x3);
2681
2682         switch (cal_mode) {
2683         case LCNPHY_CAL_FULL:
2684                 start_coeffs = syst_coeffs;
2685                 cal_cmds = commands_fullcal;
2686                 n_cal_cmds = ARRAY_SIZE(commands_fullcal);
2687                 break;
2688
2689         case LCNPHY_CAL_RECAL:
2690                 start_coeffs = syst_coeffs;
2691                 cal_cmds = commands_recal;
2692                 n_cal_cmds = ARRAY_SIZE(commands_recal);
2693                 command_nums = command_nums_recal;
2694                 break;
2695
2696         default:
2697                 break;
2698         }
2699
2700         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2701                                       start_coeffs, 11, 16, 64);
2702
2703         write_phy_reg(pi, 0x6da, 0xffff);
2704         mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
2705
2706         tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2707
2708         mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2709
2710         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2711
2712         save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
2713
2714         mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
2715
2716         mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
2717
2718         wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
2719
2720         tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2721         if (tx_gain_override_old)
2722                 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2723
2724         if (!target_gains) {
2725                 if (!tx_gain_override_old)
2726                         wlc_lcnphy_set_tx_pwr_by_index(pi,
2727                                                        pi_lcn->lcnphy_tssi_idx);
2728                 wlc_lcnphy_get_tx_gain(pi, &temp_gains);
2729                 target_gains = &temp_gains;
2730         }
2731
2732         hash = (target_gains->gm_gain << 8) |
2733                (target_gains->pga_gain << 4) | (target_gains->pad_gain);
2734
2735         band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
2736
2737         cal_gains = *target_gains;
2738         memset(ncorr_override, 0, sizeof(ncorr_override));
2739         for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
2740                 if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
2741                         cal_gains.gm_gain =
2742                                 tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
2743                         cal_gains.pga_gain =
2744                                 tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
2745                         cal_gains.pad_gain =
2746                                 tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
2747                         memcpy(ncorr_override,
2748                                &tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
2749                                sizeof(ncorr_override));
2750                         break;
2751                 }
2752         }
2753
2754         wlc_lcnphy_set_tx_gain(pi, &cal_gains);
2755
2756         write_phy_reg(pi, 0x453, 0xaa9);
2757         write_phy_reg(pi, 0x93d, 0xc0);
2758
2759         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2760                                       lcnphy_iqcal_loft_gainladder,
2761                                       ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
2762                                       16, 0);
2763
2764         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2765                                       lcnphy_iqcal_ir_gainladder,
2766                                       ARRAY_SIZE(
2767                                               lcnphy_iqcal_ir_gainladder), 16,
2768                                       32);
2769
2770         if (pi->phy_tx_tone_freq) {
2771
2772                 wlc_lcnphy_stop_tx_tone(pi);
2773                 udelay(5);
2774                 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2775         } else {
2776                 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2777         }
2778
2779         write_phy_reg(pi, 0x6da, 0xffff);
2780
2781         for (i = n_cal_start; i < n_cal_cmds; i++) {
2782                 u16 zero_diq = 0;
2783                 u16 best_coeffs[11];
2784                 u16 command_num;
2785
2786                 cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2787
2788                 command_num = command_nums[i];
2789                 if (ncorr_override[cal_type])
2790                         command_num =
2791                                 ncorr_override[cal_type] << 8 | (command_num &
2792                                                                  0xff);
2793
2794                 write_phy_reg(pi, 0x452, command_num);
2795
2796                 if ((cal_type == 3) || (cal_type == 4)) {
2797                         wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2798                                                      &diq_start, 1, 16, 69);
2799
2800                         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2801                                                       &zero_diq, 1, 16, 69);
2802                 }
2803
2804                 write_phy_reg(pi, 0x451, cal_cmds[i]);
2805
2806                 if (!wlc_lcnphy_iqcal_wait(pi))
2807                         goto cleanup;
2808
2809                 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2810                                              best_coeffs,
2811                                              ARRAY_SIZE(best_coeffs), 16, 96);
2812                 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2813                                               best_coeffs,
2814                                               ARRAY_SIZE(best_coeffs), 16, 64);
2815
2816                 if ((cal_type == 3) || (cal_type == 4))
2817                         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2818                                                       &diq_start, 1, 16, 69);
2819                 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2820                                              pi_lcn->lcnphy_cal_results.
2821                                              txiqlocal_bestcoeffs,
2822                                              ARRAY_SIZE(pi_lcn->
2823                                                         lcnphy_cal_results.
2824                                                         txiqlocal_bestcoeffs),
2825                                              16, 96);
2826         }
2827
2828         wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2829                                      pi_lcn->lcnphy_cal_results.
2830                                      txiqlocal_bestcoeffs,
2831                                      ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
2832                                                 txiqlocal_bestcoeffs), 16, 96);
2833         pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
2834
2835         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2836                                       &pi_lcn->lcnphy_cal_results.
2837                                       txiqlocal_bestcoeffs[0], 4, 16, 80);
2838
2839         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2840                                       &pi_lcn->lcnphy_cal_results.
2841                                       txiqlocal_bestcoeffs[5], 2, 16, 85);
2842
2843 cleanup:
2844         wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2845         kfree(values_to_save);
2846
2847         if (!keep_tone)
2848                 wlc_lcnphy_stop_tx_tone(pi);
2849
2850         write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2851
2852         write_phy_reg(pi, 0x453, 0);
2853
2854         if (tx_gain_override_old)
2855                 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2856         wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2857
2858         write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2859         write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2860
2861 }
2862
2863 static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
2864 {
2865         bool suspend, tx_gain_override_old;
2866         struct lcnphy_txgains old_gains;
2867         struct brcms_phy *pi = (struct brcms_phy *) ppi;
2868         u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2869             idleTssi0_regvalue_2C;
2870         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2871         u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2872         u16 SAVE_jtag_bb_afe_switch =
2873                 read_radio_reg(pi, RADIO_2064_REG007) & 1;
2874         u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2875         u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2876         u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi);
2877
2878         idleTssi = read_phy_reg(pi, 0x4ab);
2879         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2880                          MCTL_EN_MAC));
2881         if (!suspend)
2882                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2883         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2884
2885         tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2886         wlc_lcnphy_get_tx_gain(pi, &old_gains);
2887
2888         wlc_lcnphy_enable_tx_gain_override(pi);
2889         wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2890         write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2891         mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2892         mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2893         mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2894         wlc_lcnphy_tssi_setup(pi);
2895
2896         mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0));
2897         mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6));
2898
2899         wlc_lcnphy_set_bbmult(pi, 0x0);
2900
2901         wlc_phy_do_dummy_tx(pi, true, OFF);
2902         idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
2903                     >> 0);
2904
2905         idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2906                         >> 0);
2907
2908         if (idleTssi0_2C >= 256)
2909                 idleTssi0_OB = idleTssi0_2C - 256;
2910         else
2911                 idleTssi0_OB = idleTssi0_2C + 256;
2912
2913         idleTssi0_regvalue_OB = idleTssi0_OB;
2914         if (idleTssi0_regvalue_OB >= 256)
2915                 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2916         else
2917                 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2918         mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2919
2920         mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2921
2922         wlc_lcnphy_set_bbmult(pi, SAVE_bbmult);
2923         wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2924         wlc_lcnphy_set_tx_gain(pi, &old_gains);
2925         wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2926
2927         write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2928         mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2929         mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2930         mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2931         mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2932         if (!suspend)
2933                 wlapi_enable_mac(pi->sh->physhim);
2934 }
2935
2936 static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
2937 {
2938         bool suspend;
2939         u16 save_txpwrCtrlEn;
2940         u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2941         u16 auxpga_vmid;
2942         struct phytbl_info tab;
2943         u32 val;
2944         u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2945            save_reg112;
2946         u16 values_to_save[14];
2947         s8 index;
2948         int i;
2949         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2950         udelay(999);
2951
2952         save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
2953         save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
2954         save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
2955         save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
2956         save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
2957         save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
2958
2959         for (i = 0; i < 14; i++)
2960                 values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
2961         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2962                          MCTL_EN_MAC));
2963         if (!suspend)
2964                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2965         save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2966
2967         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2968         index = pi_lcn->lcnphy_current_index;
2969         wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2970         mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2971         mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2972         mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2973         mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2974
2975         mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2976
2977         mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2978
2979         mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2980
2981         mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2982
2983         mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2984
2985         mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2986
2987         mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2988
2989         mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2990
2991         mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2992
2993         mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2994
2995         mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2996
2997         mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2998
2999         mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
3000
3001         mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
3002
3003         mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
3004
3005         mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
3006
3007         mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
3008
3009         write_radio_reg(pi, RADIO_2064_REG025, 0xC);
3010
3011         mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
3012
3013         mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
3014
3015         mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
3016
3017         mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
3018
3019         val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
3020         tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
3021         tab.tbl_width = 16;
3022         tab.tbl_len = 1;
3023         tab.tbl_ptr = &val;
3024         tab.tbl_offset = 6;
3025         wlc_lcnphy_write_table(pi, &tab);
3026         if (mode == TEMPSENSE) {
3027                 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
3028
3029                 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
3030
3031                 auxpga_vmidcourse = 8;
3032                 auxpga_vmidfine = 0x4;
3033                 auxpga_gain = 2;
3034                 mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
3035         } else {
3036                 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
3037
3038                 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
3039
3040                 auxpga_vmidcourse = 7;
3041                 auxpga_vmidfine = 0xa;
3042                 auxpga_gain = 2;
3043         }
3044         auxpga_vmid =
3045                 (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
3046         mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
3047
3048         mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
3049
3050         mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
3051
3052         mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
3053
3054         mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
3055
3056         write_radio_reg(pi, RADIO_2064_REG112, 0x6);
3057
3058         wlc_phy_do_dummy_tx(pi, true, OFF);
3059         if (!tempsense_done(pi))
3060                 udelay(10);
3061
3062         write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
3063         write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
3064         write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
3065         write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
3066         write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
3067         write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
3068         for (i = 0; i < 14; i++)
3069                 write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
3070         wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
3071
3072         write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
3073         if (!suspend)
3074                 wlapi_enable_mac(pi->sh->physhim);
3075         udelay(999);
3076 }
3077
3078 static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
3079 {
3080         struct lcnphy_txgains tx_gains;
3081         u8 bbmult;
3082         struct phytbl_info tab;
3083         s32 a1, b0, b1;
3084         s32 tssi, pwr, maxtargetpwr, mintargetpwr;
3085         bool suspend;
3086         struct brcms_phy *pi = (struct brcms_phy *) ppi;
3087
3088         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
3089                          MCTL_EN_MAC));
3090         if (!suspend)
3091                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3092
3093         if (!pi->hwpwrctrl_capable) {
3094                 if (CHSPEC_IS2G(pi->radio_chanspec)) {
3095                         tx_gains.gm_gain = 4;
3096                         tx_gains.pga_gain = 12;
3097                         tx_gains.pad_gain = 12;
3098                         tx_gains.dac_gain = 0;
3099
3100                         bbmult = 150;
3101                 } else {
3102                         tx_gains.gm_gain = 7;
3103                         tx_gains.pga_gain = 15;
3104                         tx_gains.pad_gain = 14;
3105                         tx_gains.dac_gain = 0;
3106
3107                         bbmult = 150;
3108                 }
3109                 wlc_lcnphy_set_tx_gain(pi, &tx_gains);
3110                 wlc_lcnphy_set_bbmult(pi, bbmult);
3111                 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3112         } else {
3113
3114                 wlc_lcnphy_idle_tssi_est(ppi);
3115
3116                 wlc_lcnphy_clear_tx_power_offsets(pi);
3117
3118                 b0 = pi->txpa_2g[0];
3119                 b1 = pi->txpa_2g[1];
3120                 a1 = pi->txpa_2g[2];
3121                 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
3122                 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3123
3124                 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3125                 tab.tbl_width = 32;
3126                 tab.tbl_ptr = &pwr;
3127                 tab.tbl_len = 1;
3128                 tab.tbl_offset = 0;
3129                 for (tssi = 0; tssi < 128; tssi++) {
3130                         pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3131
3132                         pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3133                         wlc_lcnphy_write_table(pi, &tab);
3134                         tab.tbl_offset++;
3135                 }
3136                 mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0);
3137                 mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0);
3138                 mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8);
3139                 mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4);
3140                 mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2);
3141
3142                 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
3143
3144                 write_phy_reg(pi, 0x4a8, 10);
3145
3146                 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
3147
3148                 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3149         }
3150         if (!suspend)
3151                 wlapi_enable_mac(pi->sh->physhim);
3152 }
3153
3154 static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain)
3155 {
3156         mod_phy_reg(pi, 0x4fb,
3157                     LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
3158                     gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
3159         mod_phy_reg(pi, 0x4fd,
3160                     LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
3161                     gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
3162 }
3163
3164 void
3165 wlc_lcnphy_get_radio_loft(struct brcms_phy *pi,
3166                           u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
3167 {
3168         *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
3169         *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
3170         *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
3171         *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
3172 }
3173
3174 void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b)
3175 {
3176         struct phytbl_info tab;
3177         u16 iqcc[2];
3178
3179         iqcc[0] = a;
3180         iqcc[1] = b;
3181
3182         tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3183         tab.tbl_width = 16;
3184         tab.tbl_ptr = iqcc;
3185         tab.tbl_len = 2;
3186         tab.tbl_offset = 80;
3187         wlc_lcnphy_write_table(pi, &tab);
3188 }
3189
3190 void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq)
3191 {
3192         struct phytbl_info tab;
3193
3194         tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3195         tab.tbl_width = 16;
3196         tab.tbl_ptr = &didq;
3197         tab.tbl_len = 1;
3198         tab.tbl_offset = 85;
3199         wlc_lcnphy_write_table(pi, &tab);
3200 }
3201
3202 void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index)
3203 {
3204         struct phytbl_info tab;
3205         u16 a, b;
3206         u8 bb_mult;
3207         u32 bbmultiqcomp, txgain, locoeffs, rfpower;
3208         struct lcnphy_txgains gains;
3209         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3210
3211         pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
3212         pi_lcn->lcnphy_current_index = (u8) index;
3213
3214         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3215         tab.tbl_width = 32;
3216         tab.tbl_len = 1;
3217
3218         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3219
3220         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
3221         tab.tbl_ptr = &bbmultiqcomp;
3222         wlc_lcnphy_read_table(pi, &tab);
3223
3224         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
3225         tab.tbl_width = 32;
3226         tab.tbl_ptr = &txgain;
3227         wlc_lcnphy_read_table(pi, &tab);
3228
3229         gains.gm_gain = (u16) (txgain & 0xff);
3230         gains.pga_gain = (u16) (txgain >> 8) & 0xff;
3231         gains.pad_gain = (u16) (txgain >> 16) & 0xff;
3232         gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
3233         wlc_lcnphy_set_tx_gain(pi, &gains);
3234         wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
3235
3236         bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
3237         wlc_lcnphy_set_bbmult(pi, bb_mult);
3238
3239         wlc_lcnphy_enable_tx_gain_override(pi);
3240
3241         if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3242
3243                 a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
3244                 b = (u16) (bbmultiqcomp & 0x3ff);
3245                 wlc_lcnphy_set_tx_iqcc(pi, a, b);
3246
3247                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
3248                 tab.tbl_ptr = &locoeffs;
3249                 wlc_lcnphy_read_table(pi, &tab);
3250
3251                 wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
3252
3253                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
3254                 tab.tbl_ptr = &rfpower;
3255                 wlc_lcnphy_read_table(pi, &tab);
3256                 mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
3257
3258         }
3259 }
3260
3261 static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)
3262 {
3263         u32 j;
3264         struct phytbl_info tab;
3265         u32 temp_offset[128];
3266         tab.tbl_ptr = temp_offset;
3267         tab.tbl_len = 128;
3268         tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
3269         tab.tbl_width = 32;
3270         tab.tbl_offset = 0;
3271
3272         memset(temp_offset, 0, sizeof(temp_offset));
3273         for (j = 1; j < 128; j += 2)
3274                 temp_offset[j] = 0x80000;
3275
3276         wlc_lcnphy_write_table(pi, &tab);
3277         return;
3278 }
3279
3280 void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)
3281 {
3282         if (!bEnable) {
3283
3284                 and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
3285
3286                 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
3287
3288                 and_phy_reg(pi, 0x44c,
3289                             ~(u16) ((0x1 << 3) |
3290                                     (0x1 << 5) |
3291                                     (0x1 << 12) |
3292                                     (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3293
3294                 and_phy_reg(pi, 0x44d,
3295                             ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
3296                 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
3297
3298                 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
3299
3300                 and_phy_reg(pi, 0x4f9,
3301                             ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3302
3303                 and_phy_reg(pi, 0x4fa,
3304                             ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3305         } else {
3306
3307                 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3308                 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3309
3310                 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
3311                 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
3312
3313                 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3314                 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3315
3316                 wlc_lcnphy_set_trsw_override(pi, true, false);
3317
3318                 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
3319                 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
3320
3321                 if (CHSPEC_IS2G(pi->radio_chanspec)) {
3322
3323                         mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3324                         mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
3325
3326                         mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3327                         mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
3328
3329                         mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3330                         mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
3331
3332                         mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3333                         mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
3334
3335                         mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3336                         mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
3337                 } else {
3338
3339                         mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3340                         mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
3341
3342                         mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3343                         mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
3344
3345                         mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3346                         mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
3347
3348                         mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3349                         mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
3350
3351                         mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3352                         mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3353                 }
3354         }
3355 }
3356
3357 static void
3358 wlc_lcnphy_run_samples(struct brcms_phy *pi,
3359                        u16 num_samps,
3360                        u16 num_loops, u16 wait, bool iqcalmode)
3361 {
3362
3363         or_phy_reg(pi, 0x6da, 0x8080);
3364
3365         mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
3366         if (num_loops != 0xffff)
3367                 num_loops--;
3368         mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
3369
3370         mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
3371
3372         if (iqcalmode) {
3373
3374                 and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
3375                 or_phy_reg(pi, 0x453, (0x1 << 15));
3376         } else {
3377                 write_phy_reg(pi, 0x63f, 1);
3378                 wlc_lcnphy_tx_pu(pi, 1);
3379         }
3380
3381         or_radio_reg(pi, RADIO_2064_REG112, 0x6);
3382 }
3383
3384 void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)
3385 {
3386
3387         u8 phybw40;
3388         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3389
3390         if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
3391                 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3392                 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3393         } else {
3394                 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3395                 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3396         }
3397
3398         if (phybw40 == 0) {
3399                 mod_phy_reg((pi), 0x410,
3400                             (0x1 << 6) |
3401                             (0x1 << 5),
3402                             ((CHSPEC_IS2G(
3403                                       pi->radio_chanspec)) ? (!mode) : 0) <<
3404                             6 | (!mode) << 5);
3405                 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
3406         }
3407 }
3408
3409 void
3410 wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
3411                          bool iqcalmode)
3412 {
3413         u8 phy_bw;
3414         u16 num_samps, t, k;
3415         u32 bw;
3416         s32 theta = 0, rot = 0;
3417         struct cordic_iq tone_samp;
3418         u32 data_buf[64];
3419         u16 i_samp, q_samp;
3420         struct phytbl_info tab;
3421         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3422
3423         pi->phy_tx_tone_freq = f_kHz;
3424
3425         wlc_lcnphy_deaf_mode(pi, true);
3426
3427         phy_bw = 40;
3428         if (pi_lcn->lcnphy_spurmod) {
3429                 write_phy_reg(pi, 0x942, 0x2);
3430                 write_phy_reg(pi, 0x93b, 0x0);
3431                 write_phy_reg(pi, 0x93c, 0x0);
3432                 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3433         }
3434
3435         if (f_kHz) {
3436                 k = 1;
3437                 do {
3438                         bw = phy_bw * 1000 * k;
3439                         num_samps = bw / abs(f_kHz);
3440                         k++;
3441                 } while ((num_samps * (u32) (abs(f_kHz))) != bw);
3442         } else
3443                 num_samps = 2;
3444
3445         rot = ((f_kHz * 36) / phy_bw) / 100;
3446         theta = 0;
3447
3448         for (t = 0; t < num_samps; t++) {
3449
3450                 tone_samp = cordic_calc_iq(theta);
3451
3452                 theta += rot;
3453
3454                 i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
3455                 q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
3456                 data_buf[t] = (i_samp << 10) | q_samp;
3457         }
3458
3459         mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
3460
3461         mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
3462
3463         tab.tbl_ptr = data_buf;
3464         tab.tbl_len = num_samps;
3465         tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
3466         tab.tbl_offset = 0;
3467         tab.tbl_width = 32;
3468         wlc_lcnphy_write_table(pi, &tab);
3469
3470         wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
3471 }
3472
3473 void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
3474 {
3475         s16 playback_status;
3476         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3477
3478         pi->phy_tx_tone_freq = 0;
3479         if (pi_lcn->lcnphy_spurmod) {
3480                 write_phy_reg(pi, 0x942, 0x7);
3481                 write_phy_reg(pi, 0x93b, 0x2017);
3482                 write_phy_reg(pi, 0x93c, 0x27c5);
3483                 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3484         }
3485
3486         playback_status = read_phy_reg(pi, 0x644);
3487         if (playback_status & (0x1 << 0)) {
3488                 wlc_lcnphy_tx_pu(pi, 0);
3489                 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
3490         } else if (playback_status & (0x1 << 1))
3491                 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
3492
3493         mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
3494
3495         mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
3496
3497         mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
3498
3499         and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
3500
3501         wlc_lcnphy_deaf_mode(pi, false);
3502 }
3503
3504 static void
3505 wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3506 {
3507         u16 di0dq0;
3508         u16 x, y, data_rf;
3509         int k;
3510         switch (cal_type) {
3511         case 0:
3512                 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3513                 break;
3514         case 2:
3515                 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3516                 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3517                 break;
3518         case 3:
3519                 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3520                 y = 8 + k;
3521                 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3522                 x = 8 - k;
3523                 data_rf = (x * 16 + y);
3524                 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3525                 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3526                 y = 8 + k;
3527                 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3528                 x = 8 - k;
3529                 data_rf = (x * 16 + y);
3530                 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3531                 break;
3532         case 4:
3533                 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3534                 y = 8 + k;
3535                 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3536                 x = 8 - k;
3537                 data_rf = (x * 16 + y);
3538                 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3539                 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3540                 y = 8 + k;
3541                 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3542                 x = 8 - k;
3543                 data_rf = (x * 16 + y);
3544                 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3545                 break;
3546         }
3547 }
3548
3549 static struct lcnphy_unsign16_struct
3550 wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
3551 {
3552         u16 a, b, didq;
3553         u8 di0, dq0, ei, eq, fi, fq;
3554         struct lcnphy_unsign16_struct cc;
3555         cc.re = 0;
3556         cc.im = 0;
3557         switch (cal_type) {
3558         case 0:
3559                 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3560                 cc.re = a;
3561                 cc.im = b;
3562                 break;
3563         case 2:
3564                 didq = wlc_lcnphy_get_tx_locc(pi);
3565                 di0 = (((didq & 0xff00) << 16) >> 24);
3566                 dq0 = (((didq & 0x00ff) << 24) >> 24);
3567                 cc.re = (u16) di0;
3568                 cc.im = (u16) dq0;
3569                 break;
3570         case 3:
3571                 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3572                 cc.re = (u16) ei;
3573                 cc.im = (u16) eq;
3574                 break;
3575         case 4:
3576                 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3577                 cc.re = (u16) fi;
3578                 cc.im = (u16) fq;
3579                 break;
3580         }
3581         return cc;
3582 }
3583
3584 static void
3585 wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
3586                     s16 *ptr, int mode)
3587 {
3588         u32 curval1, curval2, stpptr, curptr, strptr, val;
3589         u16 sslpnCalibClkEnCtrl, timer;
3590         u16 old_sslpnCalibClkEnCtrl;
3591         s16 imag, real;
3592         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3593
3594         timer = 0;
3595         old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3596
3597         curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));
3598         ptr[130] = 0;
3599         bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),
3600                      ((1 << 6) | curval1));
3601
3602         bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);
3603         bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);
3604         udelay(20);
3605         curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));
3606         bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),
3607                      curval2 | 0x30);
3608
3609         write_phy_reg(pi, 0x555, 0x0);
3610         write_phy_reg(pi, 0x5a6, 0x5);
3611
3612         write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3613         write_phy_reg(pi, 0x5cf, 3);
3614         write_phy_reg(pi, 0x5a5, 0x3);
3615         write_phy_reg(pi, 0x583, 0x0);
3616         write_phy_reg(pi, 0x584, 0x0);
3617         write_phy_reg(pi, 0x585, 0x0fff);
3618         write_phy_reg(pi, 0x586, 0x0000);
3619
3620         write_phy_reg(pi, 0x580, 0x4501);
3621
3622         sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3623         write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3624         stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));
3625         curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3626         do {
3627                 udelay(10);
3628                 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3629                 timer++;
3630         } while ((curptr != stpptr) && (timer < 500));
3631
3632         bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);
3633         strptr = 0x7E00;
3634         bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);
3635         while (strptr < 0x8000) {
3636                 val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));
3637                 imag = ((val >> 16) & 0x3ff);
3638                 real = ((val) & 0x3ff);
3639                 if (imag > 511)
3640                         imag -= 1024;
3641
3642                 if (real > 511)
3643                         real -= 1024;
3644
3645                 if (pi_lcn->lcnphy_iqcal_swp_dis)
3646                         ptr[(strptr - 0x7E00) / 4] = real;
3647                 else
3648                         ptr[(strptr - 0x7E00) / 4] = imag;
3649
3650                 if (clip_detect_algo) {
3651                         if (imag > thresh || imag < -thresh) {
3652                                 strptr = 0x8000;
3653                                 ptr[130] = 1;
3654                         }
3655                 }
3656
3657                 strptr += 4;
3658         }
3659
3660         write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3661         bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);
3662         bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);
3663 }
3664
3665 static void
3666 wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
3667               int step_size_lg2)
3668 {
3669         const struct lcnphy_spb_tone *phy_c1;
3670         struct lcnphy_spb_tone phy_c2;
3671         struct lcnphy_unsign16_struct phy_c3;
3672         int phy_c4, phy_c5, k, l, j, phy_c6;
3673         u16 phy_c7, phy_c8, phy_c9;
3674         s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
3675         s16 *ptr, phy_c17;
3676         s32 phy_c18, phy_c19;
3677         u32 phy_c20, phy_c21;
3678         bool phy_c22, phy_c23, phy_c24, phy_c25;
3679         u16 phy_c26, phy_c27;
3680         u16 phy_c28, phy_c29, phy_c30;
3681         u16 phy_c31;
3682         u16 *phy_c32;
3683         phy_c21 = 0;
3684         phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
3685         ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
3686         if (NULL == ptr)
3687                 return;
3688
3689         phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
3690         if (NULL == phy_c32) {
3691                 kfree(ptr);
3692                 return;
3693         }
3694         phy_c26 = read_phy_reg(pi, 0x6da);
3695         phy_c27 = read_phy_reg(pi, 0x6db);
3696         phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
3697         write_phy_reg(pi, 0x93d, 0xC0);
3698
3699         wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
3700         write_phy_reg(pi, 0x6da, 0xffff);
3701         or_phy_reg(pi, 0x6db, 0x3);
3702
3703         wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
3704         udelay(500);
3705         phy_c28 = read_phy_reg(pi, 0x938);
3706         phy_c29 = read_phy_reg(pi, 0x4d7);
3707         phy_c30 = read_phy_reg(pi, 0x4d8);
3708         or_phy_reg(pi, 0x938, 0x1 << 2);
3709         or_phy_reg(pi, 0x4d7, 0x1 << 2);
3710         or_phy_reg(pi, 0x4d7, 0x1 << 3);
3711         mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
3712         or_phy_reg(pi, 0x4d8, 1 << 0);
3713         or_phy_reg(pi, 0x4d8, 1 << 1);
3714         mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
3715         mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
3716         phy_c1 = &lcnphy_spb_tone_3750[0];
3717         phy_c4 = 32;
3718
3719         if (num_levels == 0) {
3720                 if (cal_type != 0)
3721                         num_levels = 4;
3722                 else
3723                         num_levels = 9;
3724         }
3725         if (step_size_lg2 == 0) {
3726                 if (cal_type != 0)
3727                         step_size_lg2 = 3;
3728                 else
3729                         step_size_lg2 = 8;
3730         }
3731
3732         phy_c7 = (1 << step_size_lg2);
3733         phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
3734         phy_c15 = (s16) phy_c3.re;
3735         phy_c16 = (s16) phy_c3.im;
3736         if (cal_type == 2) {
3737                 if (phy_c3.re > 127)
3738                         phy_c15 = phy_c3.re - 256;
3739                 if (phy_c3.im > 127)
3740                         phy_c16 = phy_c3.im - 256;
3741         }
3742         wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3743         udelay(20);
3744         for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
3745                 phy_c23 = true;
3746                 phy_c22 = false;
3747                 switch (cal_type) {
3748                 case 0:
3749                         phy_c10 = 511;
3750                         break;
3751                 case 2:
3752                         phy_c10 = 127;
3753                         break;
3754                 case 3:
3755                         phy_c10 = 15;
3756                         break;
3757                 case 4:
3758                         phy_c10 = 15;
3759                         break;
3760                 }
3761
3762                 phy_c9 = read_phy_reg(pi, 0x93d);
3763                 phy_c9 = 2 * phy_c9;
3764                 phy_c24 = false;
3765                 phy_c5 = 7;
3766                 phy_c25 = true;
3767                 while (1) {
3768                         write_radio_reg(pi, RADIO_2064_REG026,
3769                                         (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
3770                         udelay(50);
3771                         phy_c22 = false;
3772                         ptr[130] = 0;
3773                         wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
3774                         if (ptr[130] == 1)
3775                                 phy_c22 = true;
3776                         if (phy_c22)
3777                                 phy_c5 -= 1;
3778                         if ((phy_c22 != phy_c24) && (!phy_c25))
3779                                 break;
3780                         if (!phy_c22)
3781                                 phy_c5 += 1;
3782                         if (phy_c5 <= 0 || phy_c5 >= 7)
3783                                 break;
3784                         phy_c24 = phy_c22;
3785                         phy_c25 = false;
3786                 }
3787
3788                 if (phy_c5 < 0)
3789                         phy_c5 = 0;
3790                 else if (phy_c5 > 7)
3791                         phy_c5 = 7;
3792
3793                 for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
3794                         for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
3795                                 phy_c11 = phy_c15 + k;
3796                                 phy_c12 = phy_c16 + l;
3797
3798                                 if (phy_c11 < -phy_c10)
3799                                         phy_c11 = -phy_c10;
3800                                 else if (phy_c11 > phy_c10)
3801                                         phy_c11 = phy_c10;
3802                                 if (phy_c12 < -phy_c10)
3803                                         phy_c12 = -phy_c10;
3804                                 else if (phy_c12 > phy_c10)
3805                                         phy_c12 = phy_c10;
3806                                 wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
3807                                                   phy_c12);
3808                                 udelay(20);
3809                                 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
3810
3811                                 phy_c18 = 0;
3812                                 phy_c19 = 0;
3813                                 for (j = 0; j < 128; j++) {
3814                                         if (cal_type != 0)
3815                                                 phy_c6 = j % phy_c4;
3816                                         else
3817                                                 phy_c6 = (2 * j) % phy_c4;
3818
3819                                         phy_c2.re = phy_c1[phy_c6].re;
3820                                         phy_c2.im = phy_c1[phy_c6].im;
3821                                         phy_c17 = ptr[j];
3822                                         phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
3823                                         phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
3824                                 }
3825
3826                                 phy_c18 = phy_c18 >> 10;
3827                                 phy_c19 = phy_c19 >> 10;
3828                                 phy_c20 = ((phy_c18 * phy_c18) +
3829                                            (phy_c19 * phy_c19));
3830
3831                                 if (phy_c23 || phy_c20 < phy_c21) {
3832                                         phy_c21 = phy_c20;
3833                                         phy_c13 = phy_c11;
3834                                         phy_c14 = phy_c12;
3835                                 }
3836                                 phy_c23 = false;
3837                         }
3838                 }
3839                 phy_c23 = true;
3840                 phy_c15 = phy_c13;
3841                 phy_c16 = phy_c14;
3842                 phy_c7 = phy_c7 >> 1;
3843                 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3844                 udelay(20);
3845         }
3846         goto cleanup;
3847 cleanup:
3848         wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
3849         wlc_lcnphy_stop_tx_tone(pi);
3850         write_phy_reg(pi, 0x6da, phy_c26);
3851         write_phy_reg(pi, 0x6db, phy_c27);
3852         write_phy_reg(pi, 0x938, phy_c28);
3853         write_phy_reg(pi, 0x4d7, phy_c29);
3854         write_phy_reg(pi, 0x4d8, phy_c30);
3855         write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
3856
3857         kfree(phy_c32);
3858         kfree(ptr);
3859 }
3860
3861 void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
3862 {
3863         u16 iqcc[2];
3864         struct phytbl_info tab;
3865
3866         tab.tbl_ptr = iqcc;
3867         tab.tbl_len = 2;
3868         tab.tbl_id = 0;
3869         tab.tbl_offset = 80;
3870         tab.tbl_width = 16;
3871         wlc_lcnphy_read_table(pi, &tab);
3872
3873         *a = iqcc[0];
3874         *b = iqcc[1];
3875 }
3876
3877 static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
3878 {
3879         struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3880
3881         wlc_lcnphy_set_cc(pi, 0, 0, 0);
3882         wlc_lcnphy_set_cc(pi, 2, 0, 0);
3883         wlc_lcnphy_set_cc(pi, 3, 0, 0);
3884         wlc_lcnphy_set_cc(pi, 4, 0, 0);
3885
3886         wlc_lcnphy_a1(pi, 4, 0, 0);
3887         wlc_lcnphy_a1(pi, 3, 0, 0);
3888         wlc_lcnphy_a1(pi, 2, 3, 2);
3889         wlc_lcnphy_a1(pi, 0, 5, 8);
3890         wlc_lcnphy_a1(pi, 2, 2, 1);
3891         wlc_lcnphy_a1(pi, 0, 4, 3);
3892
3893         iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3894         locc2 = wlc_lcnphy_get_cc(pi, 2);
3895         locc3 = wlc_lcnphy_get_cc(pi, 3);
3896         locc4 = wlc_lcnphy_get_cc(pi, 4);
3897 }
3898
3899 u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
3900 {
3901         struct phytbl_info tab;
3902         u16 didq;
3903
3904         tab.tbl_id = 0;
3905         tab.tbl_width = 16;
3906         tab.tbl_ptr = &didq;
3907         tab.tbl_len = 1;
3908         tab.tbl_offset = 85;
3909         wlc_lcnphy_read_table(pi, &tab);
3910
3911         return didq;
3912 }
3913
3914 static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
3915 {
3916
3917         struct lcnphy_txgains target_gains, old_gains;
3918         u8 save_bb_mult;
3919         u16 a, b, didq, save_pa_gain = 0;
3920         uint idx, SAVE_txpwrindex = 0xFF;
3921         u32 val;
3922         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3923         struct phytbl_info tab;
3924         u8 ei0, eq0, fi0, fq0;
3925         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3926
3927         wlc_lcnphy_get_tx_gain(pi, &old_gains);
3928         save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
3929
3930         save_bb_mult = wlc_lcnphy_get_bbmult(pi);
3931
3932         if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
3933                 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
3934
3935         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3936
3937         target_gains.gm_gain = 7;
3938         target_gains.pga_gain = 0;
3939         target_gains.pad_gain = 21;
3940         target_gains.dac_gain = 0;
3941         wlc_lcnphy_set_tx_gain(pi, &target_gains);
3942
3943         if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
3944
3945                 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
3946
3947                 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3948                                        (pi_lcn->
3949                                         lcnphy_recal ? LCNPHY_CAL_RECAL :
3950                                         LCNPHY_CAL_FULL), false);
3951         } else {
3952                 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3953                 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3954         }
3955
3956         wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
3957         if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
3958                 if (CHSPEC_IS5G(pi->radio_chanspec)) {
3959                         target_gains.gm_gain = 255;
3960                         target_gains.pga_gain = 255;
3961                         target_gains.pad_gain = 0xf0;
3962                         target_gains.dac_gain = 0;
3963                 } else {
3964                         target_gains.gm_gain = 7;
3965                         target_gains.pga_gain = 45;
3966                         target_gains.pad_gain = 186;
3967                         target_gains.dac_gain = 0;
3968                 }
3969
3970                 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
3971                     || pi_lcn->lcnphy_hw_iqcal_en) {
3972
3973                         target_gains.pga_gain = 0;
3974                         target_gains.pad_gain = 30;
3975                         wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3976                         wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3977                                                LCNPHY_CAL_FULL, false);
3978                 } else {
3979                         wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3980                 }
3981         }
3982
3983         wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3984
3985         didq = wlc_lcnphy_get_tx_locc(pi);
3986
3987         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3988         tab.tbl_width = 32;
3989         tab.tbl_ptr = &val;
3990
3991         tab.tbl_len = 1;
3992         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
3993
3994         for (idx = 0; idx < 128; idx++) {
3995                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
3996
3997                 wlc_lcnphy_read_table(pi, &tab);
3998                 val = (val & 0xfff00000) |
3999                       ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
4000                 wlc_lcnphy_write_table(pi, &tab);
4001
4002                 val = didq;
4003                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
4004                 wlc_lcnphy_write_table(pi, &tab);
4005         }
4006
4007         pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
4008         pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
4009         pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
4010         pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
4011         pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
4012         pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
4013         pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
4014
4015         wlc_lcnphy_set_bbmult(pi, save_bb_mult);
4016         wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
4017         wlc_lcnphy_set_tx_gain(pi, &old_gains);
4018
4019         if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
4020                 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4021         else
4022                 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
4023 }
4024
4025 s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
4026 {
4027         u16 tempsenseval1, tempsenseval2;
4028         s16 avg = 0;
4029         bool suspend = false;
4030
4031         if (mode == 1) {
4032                 suspend = (0 == (bcma_read32(pi->d11core,
4033                                              D11REGOFFS(maccontrol)) &
4034                                  MCTL_EN_MAC));
4035                 if (!suspend)
4036                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
4037                 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4038         }
4039         tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4040         tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4041
4042         if (tempsenseval1 > 255)
4043                 avg = (s16) (tempsenseval1 - 512);
4044         else
4045                 avg = (s16) tempsenseval1;
4046
4047         if (tempsenseval2 > 255)
4048                 avg += (s16) (tempsenseval2 - 512);
4049         else
4050                 avg += (s16) tempsenseval2;
4051
4052         avg /= 2;
4053
4054         if (mode == 1) {
4055
4056                 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4057
4058                 udelay(100);
4059                 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4060
4061                 if (!suspend)
4062                         wlapi_enable_mac(pi->sh->physhim);
4063         }
4064         return avg;
4065 }
4066
4067 u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
4068 {
4069         u16 tempsenseval1, tempsenseval2;
4070         s32 avg = 0;
4071         bool suspend = false;
4072         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4073         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4074
4075         if (mode == 1) {
4076                 suspend = (0 == (bcma_read32(pi->d11core,
4077                                              D11REGOFFS(maccontrol)) &
4078                                  MCTL_EN_MAC));
4079                 if (!suspend)
4080                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
4081                 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4082         }
4083         tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4084         tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4085
4086         if (tempsenseval1 > 255)
4087                 avg = (int)(tempsenseval1 - 512);
4088         else
4089                 avg = (int)tempsenseval1;
4090
4091         if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
4092                 if (tempsenseval2 > 255)
4093                         avg = (int)(avg - tempsenseval2 + 512);
4094                 else
4095                         avg = (int)(avg - tempsenseval2);
4096         } else {
4097                 if (tempsenseval2 > 255)
4098                         avg = (int)(avg + tempsenseval2 - 512);
4099                 else
4100                         avg = (int)(avg + tempsenseval2);
4101                 avg = avg / 2;
4102         }
4103         if (avg < 0)
4104                 avg = avg + 512;
4105
4106         if (pi_lcn->lcnphy_tempsense_option == 2)
4107                 avg = tempsenseval1;
4108
4109         if (mode)
4110                 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4111
4112         if (mode == 1) {
4113
4114                 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4115
4116                 udelay(100);
4117                 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4118
4119                 if (!suspend)
4120                         wlapi_enable_mac(pi->sh->physhim);
4121         }
4122         return (u16) avg;
4123 }
4124
4125 s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
4126 {
4127         s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
4128         degree =
4129                 ((degree <<
4130                   10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
4131                 / LCN_TEMPSENSE_DEN;
4132         return (s8) degree;
4133 }
4134
4135 s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
4136 {
4137         u16 vbatsenseval;
4138         s32 avg = 0;
4139         bool suspend = false;
4140
4141         if (mode == 1) {
4142                 suspend = (0 == (bcma_read32(pi->d11core,
4143                                              D11REGOFFS(maccontrol)) &
4144                                  MCTL_EN_MAC));
4145                 if (!suspend)
4146                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
4147                 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
4148         }
4149
4150         vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
4151
4152         if (vbatsenseval > 255)
4153                 avg = (s32) (vbatsenseval - 512);
4154         else
4155                 avg = (s32) vbatsenseval;
4156
4157         avg =   (avg * LCN_VBAT_SCALE_NOM +
4158                  (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
4159
4160         if (mode == 1) {
4161                 if (!suspend)
4162                         wlapi_enable_mac(pi->sh->physhim);
4163         }
4164         return (s8) avg;
4165 }
4166
4167 static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
4168 {
4169         u8 phybw40;
4170         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4171
4172         mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
4173
4174         if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
4175             (mode == AFE_CLK_INIT_MODE_TXRX2X))
4176                 write_phy_reg(pi, 0x6d0, 0x7);
4177
4178         wlc_lcnphy_toggle_afe_pwdn(pi);
4179 }
4180
4181 static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4182 {
4183 }
4184
4185 static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
4186 {
4187         bool suspend;
4188         s8 index;
4189         u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4190         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4191         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4192                          MCTL_EN_MAC));
4193         if (!suspend)
4194                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4195         wlc_lcnphy_deaf_mode(pi, true);
4196         pi->phy_lastcal = pi->sh->now;
4197         pi->phy_forcecal = false;
4198         index = pi_lcn->lcnphy_current_index;
4199
4200         wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4201
4202         wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4203         wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4204         wlc_lcnphy_deaf_mode(pi, false);
4205         if (!suspend)
4206                 wlapi_enable_mac(pi->sh->physhim);
4207
4208 }
4209
4210 static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
4211 {
4212         bool suspend, full_cal;
4213         const struct lcnphy_rx_iqcomp *rx_iqcomp;
4214         int rx_iqcomp_sz;
4215         u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4216         s8 index;
4217         struct phytbl_info tab;
4218         s32 a1, b0, b1;
4219         s32 tssi, pwr, maxtargetpwr, mintargetpwr;
4220         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4221
4222         pi->phy_lastcal = pi->sh->now;
4223         pi->phy_forcecal = false;
4224         full_cal =
4225                 (pi_lcn->lcnphy_full_cal_channel !=
4226                  CHSPEC_CHANNEL(pi->radio_chanspec));
4227         pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
4228         index = pi_lcn->lcnphy_current_index;
4229
4230         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4231                          MCTL_EN_MAC));
4232         if (!suspend) {
4233                 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
4234                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4235         }
4236
4237         wlc_lcnphy_deaf_mode(pi, true);
4238
4239         wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4240
4241         rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
4242         rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
4243
4244         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4245                 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
4246         else
4247                 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
4248
4249         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4250
4251                 wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
4252
4253                 b0 = pi->txpa_2g[0];
4254                 b1 = pi->txpa_2g[1];
4255                 a1 = pi->txpa_2g[2];
4256                 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
4257                 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
4258
4259                 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4260                 tab.tbl_width = 32;
4261                 tab.tbl_ptr = &pwr;
4262                 tab.tbl_len = 1;
4263                 tab.tbl_offset = 0;
4264                 for (tssi = 0; tssi < 128; tssi++) {
4265                         pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
4266                         pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
4267                         wlc_lcnphy_write_table(pi, &tab);
4268                         tab.tbl_offset++;
4269                 }
4270         }
4271
4272         wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4273         wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4274         wlc_lcnphy_deaf_mode(pi, false);
4275         if (!suspend)
4276                 wlapi_enable_mac(pi->sh->physhim);
4277 }
4278
4279 void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
4280 {
4281         u16 temp_new;
4282         int temp1, temp2, temp_diff;
4283         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4284
4285         switch (mode) {
4286         case PHY_PERICAL_CHAN:
4287                 break;
4288         case PHY_FULLCAL:
4289                 wlc_lcnphy_periodic_cal(pi);
4290                 break;
4291         case PHY_PERICAL_PHYINIT:
4292                 wlc_lcnphy_periodic_cal(pi);
4293                 break;
4294         case PHY_PERICAL_WATCHDOG:
4295                 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4296                         temp_new = wlc_lcnphy_tempsense(pi, 0);
4297                         temp1 = LCNPHY_TEMPSENSE(temp_new);
4298                         temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
4299                         temp_diff = temp1 - temp2;
4300                         if ((pi_lcn->lcnphy_cal_counter > 90) ||
4301                             (temp_diff > 60) || (temp_diff < -60)) {
4302                                 wlc_lcnphy_glacial_timer_based_cal(pi);
4303                                 wlc_2064_vco_cal(pi);
4304                                 pi_lcn->lcnphy_cal_temper = temp_new;
4305                                 pi_lcn->lcnphy_cal_counter = 0;
4306                         } else
4307                                 pi_lcn->lcnphy_cal_counter++;
4308                 }
4309                 break;
4310         case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
4311                 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4312                         wlc_lcnphy_tx_power_adjustment(
4313                                 (struct brcms_phy_pub *) pi);
4314                 break;
4315         }
4316 }
4317
4318 void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
4319 {
4320         s8 cck_offset;
4321         u16 status;
4322         status = (read_phy_reg(pi, 0x4ab));
4323         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
4324             (status  & (0x1 << 15))) {
4325                 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
4326                                    >> 0) >> 1);
4327
4328                 if (wlc_phy_tpc_isenabled_lcnphy(pi))
4329                         cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
4330                 else
4331                         cck_offset = 0;
4332
4333                 *cck_pwr = *ofdm_pwr + cck_offset;
4334         } else {
4335                 *cck_pwr = 0;
4336                 *ofdm_pwr = 0;
4337         }
4338 }
4339
4340 void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4341 {
4342         return;
4343
4344 }
4345
4346 void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
4347 {
4348         s8 index;
4349         u16 index2;
4350         struct brcms_phy *pi = (struct brcms_phy *) ppi;
4351         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4352         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4353         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
4354             SAVE_txpwrctrl) {
4355                 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
4356                 index2 = (u16) (index * 2);
4357                 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
4358
4359                 pi_lcn->lcnphy_current_index =
4360                         (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
4361         }
4362 }
4363
4364 static void
4365 wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
4366                               const struct lcnphy_tx_gain_tbl_entry *gain_table)
4367 {
4368         u32 j;
4369         struct phytbl_info tab;
4370         u32 val;
4371         u16 pa_gain;
4372         u16 gm_gain;
4373
4374         if (CHSPEC_IS5G(pi->radio_chanspec))
4375                 pa_gain = 0x70;
4376         else
4377                 pa_gain = 0x60;
4378
4379         if (pi->sh->boardflags & BFL_FEM)
4380                 pa_gain = 0x10;
4381
4382         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4383         tab.tbl_width = 32;
4384         tab.tbl_len = 1;
4385         tab.tbl_ptr = &val;
4386
4387         for (j = 0; j < 128; j++) {
4388                 if (pi->sh->boardflags & BFL_FEM)
4389                         gm_gain = gain_table[j].gm;
4390                 else
4391                         gm_gain = 15;
4392
4393                 val = (((u32) pa_gain << 24) |
4394                        (gain_table[j].pad << 16) |
4395                        (gain_table[j].pga << 8) | gm_gain);
4396
4397                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4398                 wlc_lcnphy_write_table(pi, &tab);
4399
4400                 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4401                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4402                 wlc_lcnphy_write_table(pi, &tab);
4403         }
4404 }
4405
4406 static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
4407 {
4408         struct phytbl_info tab;
4409         u32 val, bbmult, rfgain;
4410         u8 index;
4411         u8 scale_factor = 1;
4412         s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4413
4414         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4415         tab.tbl_width = 32;
4416         tab.tbl_len = 1;
4417
4418         for (index = 0; index < 128; index++) {
4419                 tab.tbl_ptr = &bbmult;
4420                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4421                 wlc_lcnphy_read_table(pi, &tab);
4422                 bbmult = bbmult >> 20;
4423
4424                 tab.tbl_ptr = &rfgain;
4425                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4426                 wlc_lcnphy_read_table(pi, &tab);
4427
4428                 qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4429                 qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4430
4431                 if (qQ1 < qQ2) {
4432                         temp2 = qm_shr16(temp2, qQ2 - qQ1);
4433                         qQ = qQ1;
4434                 } else {
4435                         temp1 = qm_shr16(temp1, qQ1 - qQ2);
4436                         qQ = qQ2;
4437                 }
4438                 temp = qm_sub16(temp1, temp2);
4439
4440                 if (qQ >= 4)
4441                         shift = qQ - 4;
4442                 else
4443                         shift = 4 - qQ;
4444
4445                 val = (((index << shift) + (5 * temp) +
4446                         (1 << (scale_factor + shift - 3))) >> (scale_factor +
4447                                                                shift - 2));
4448
4449                 tab.tbl_ptr = &val;
4450                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4451                 wlc_lcnphy_write_table(pi, &tab);
4452         }
4453 }
4454
4455 static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
4456 {
4457         or_phy_reg(pi, 0x805, 0x1);
4458
4459         mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4460
4461         mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4462
4463         write_phy_reg(pi, 0x414, 0x1e10);
4464         write_phy_reg(pi, 0x415, 0x0640);
4465
4466         mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4467
4468         or_phy_reg(pi, 0x44a, 0x44);
4469         write_phy_reg(pi, 0x44a, 0x80);
4470         mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4471
4472         mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4473
4474         if (!(pi->sh->boardrev < 0x1204))
4475                 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4476
4477         write_phy_reg(pi, 0x7d6, 0x0902);
4478         mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4479
4480         mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4481
4482         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4483                 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4484
4485                 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4486
4487                 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4488
4489                 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4490
4491                 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4492
4493                 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4494                 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4495                 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4496                 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4497                 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4498
4499                 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4500
4501                 wlc_lcnphy_clear_tx_power_offsets(pi);
4502                 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4503
4504         }
4505 }
4506
4507 static void wlc_lcnphy_rcal(struct brcms_phy *pi)
4508 {
4509         u8 rcal_value;
4510
4511         and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4512
4513         or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4514         or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4515
4516         or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4517         or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4518
4519         or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4520
4521         or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4522         mdelay(5);
4523         SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4524
4525         if (wlc_radio_2064_rcal_done(pi)) {
4526                 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4527                 rcal_value = rcal_value & 0x1f;
4528         }
4529
4530         and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4531
4532         and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4533 }
4534
4535 static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
4536 {
4537         u8 dflt_rc_cal_val;
4538         u16 flt_val;
4539
4540         dflt_rc_cal_val = 7;
4541         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4542                 dflt_rc_cal_val = 11;
4543         flt_val =
4544                 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4545                 (dflt_rc_cal_val);
4546         write_phy_reg(pi, 0x933, flt_val);
4547         write_phy_reg(pi, 0x934, flt_val);
4548         write_phy_reg(pi, 0x935, flt_val);
4549         write_phy_reg(pi, 0x936, flt_val);
4550         write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4551
4552         return;
4553 }
4554
4555 static void wlc_radio_2064_init(struct brcms_phy *pi)
4556 {
4557         u32 i;
4558         const struct lcnphy_radio_regs *lcnphyregs = NULL;
4559
4560         lcnphyregs = lcnphy_radio_regs_2064;
4561
4562         for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4563                 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4564                         write_radio_reg(pi,
4565                                         ((lcnphyregs[i].address & 0x3fff) |
4566                                          RADIO_DEFAULT_CORE),
4567                                         (u16) lcnphyregs[i].init_a);
4568                 else if (lcnphyregs[i].do_init_g)
4569                         write_radio_reg(pi,
4570                                         ((lcnphyregs[i].address & 0x3fff) |
4571                                          RADIO_DEFAULT_CORE),
4572                                         (u16) lcnphyregs[i].init_g);
4573
4574         write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4575         write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4576
4577         write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4578
4579         write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4580
4581         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4582
4583                 write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4584                 write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4585                 write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4586         }
4587
4588         write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4589         write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4590
4591         mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4592
4593         mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4594
4595         mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4596
4597         mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4598
4599         mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4600
4601         write_phy_reg(pi, 0x4ea, 0x4688);
4602
4603         if (pi->sh->boardflags & BFL_FEM)
4604                 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4605         else
4606                 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);
4607
4608         mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4609
4610         mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4611
4612         wlc_lcnphy_set_tx_locc(pi, 0);
4613
4614         wlc_lcnphy_rcal(pi);
4615
4616         wlc_lcnphy_rc_cal(pi);
4617
4618         if (!(pi->sh->boardflags & BFL_FEM)) {
4619                 write_radio_reg(pi, RADIO_2064_REG032, 0x6f);
4620                 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4621                 write_radio_reg(pi, RADIO_2064_REG039, 0xe);
4622         }
4623
4624 }
4625
4626 static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4627 {
4628         wlc_radio_2064_init(pi);
4629 }
4630
4631 static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
4632 {
4633         uint idx;
4634         u8 phybw40;
4635         struct phytbl_info tab;
4636         u32 val;
4637
4638         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4639
4640         for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
4641                 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4642
4643         if (pi->sh->boardflags & BFL_FEM_BT) {
4644                 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4645                 tab.tbl_width = 16;
4646                 tab.tbl_ptr = &val;
4647                 tab.tbl_len = 1;
4648                 val = 100;
4649                 tab.tbl_offset = 4;
4650                 wlc_lcnphy_write_table(pi, &tab);
4651         }
4652
4653         if (!(pi->sh->boardflags & BFL_FEM)) {
4654                 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4655                 tab.tbl_width = 16;
4656                 tab.tbl_ptr = &val;
4657                 tab.tbl_len = 1;
4658
4659                 val = 150;
4660                 tab.tbl_offset = 0;
4661                 wlc_lcnphy_write_table(pi, &tab);
4662
4663                 val = 220;
4664                 tab.tbl_offset = 1;
4665                 wlc_lcnphy_write_table(pi, &tab);
4666         }
4667
4668         if (CHSPEC_IS2G(pi->radio_chanspec)) {
4669                 if (pi->sh->boardflags & BFL_FEM)
4670                         wlc_lcnphy_load_tx_gain_table(
4671                                 pi,
4672                                 dot11lcnphy_2GHz_extPA_gaintable_rev0);
4673                 else
4674                         wlc_lcnphy_load_tx_gain_table(
4675                                 pi,
4676                                 dot11lcnphy_2GHz_gaintable_rev0);
4677         }
4678
4679         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4680                 const struct phytbl_info *tb;
4681                 int l;
4682
4683                 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4684                         l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4685                         if (pi->sh->boardflags & BFL_EXTLNA)
4686                                 tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
4687                         else
4688                                 tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
4689                 } else {
4690                         l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4691                         if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4692                                 tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
4693                         else
4694                                 tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
4695                 }
4696
4697                 for (idx = 0; idx < l; idx++)
4698                         wlc_lcnphy_write_table(pi, &tb[idx]);
4699         }
4700
4701         if ((pi->sh->boardflags & BFL_FEM)
4702             && !(pi->sh->boardflags & BFL_FEM_BT))
4703                 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
4704         else if (pi->sh->boardflags & BFL_FEM_BT) {
4705                 if (pi->sh->boardrev < 0x1250)
4706                         wlc_lcnphy_write_table(
4707                                 pi,
4708                                 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
4709                 else
4710                         wlc_lcnphy_write_table(
4711                                 pi,
4712                                 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
4713         } else
4714                 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
4715
4716         wlc_lcnphy_load_rfpower(pi);
4717
4718         wlc_lcnphy_clear_papd_comptable(pi);
4719 }
4720
4721 static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
4722 {
4723         u16 afectrl1;
4724         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4725
4726         write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4727
4728         write_phy_reg(pi, 0x43b, 0x0);
4729         write_phy_reg(pi, 0x43c, 0x0);
4730         write_phy_reg(pi, 0x44c, 0x0);
4731         write_phy_reg(pi, 0x4e6, 0x0);
4732         write_phy_reg(pi, 0x4f9, 0x0);
4733         write_phy_reg(pi, 0x4b0, 0x0);
4734         write_phy_reg(pi, 0x938, 0x0);
4735         write_phy_reg(pi, 0x4b0, 0x0);
4736         write_phy_reg(pi, 0x44e, 0);
4737
4738         or_phy_reg(pi, 0x567, 0x03);
4739
4740         or_phy_reg(pi, 0x44a, 0x44);
4741         write_phy_reg(pi, 0x44a, 0x80);
4742
4743         if (!(pi->sh->boardflags & BFL_FEM))
4744                 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4745
4746         if (0) {
4747                 afectrl1 = 0;
4748                 afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4749                                   (pi_lcn->lcnphy_rssi_vc << 4) |
4750                                   (pi_lcn->lcnphy_rssi_gs << 10));
4751                 write_phy_reg(pi, 0x43e, afectrl1);
4752         }
4753
4754         mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4755         if (pi->sh->boardflags & BFL_FEM) {
4756                 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4757
4758                 write_phy_reg(pi, 0x910, 0x1);
4759         }
4760
4761         mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4762         mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4763         mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4764
4765 }
4766
4767 static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
4768 {
4769         if (CHSPEC_IS5G(pi->radio_chanspec)) {
4770                 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4771                 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4772         }
4773 }
4774
4775 static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
4776 {
4777         s16 temp;
4778         struct phytbl_info tab;
4779         u32 tableBuffer[2];
4780         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4781
4782         temp = (s16) read_phy_reg(pi, 0x4df);
4783         pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4784
4785         if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4786                 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4787
4788         pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4789
4790         if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4791                 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4792
4793         tab.tbl_ptr = tableBuffer;
4794         tab.tbl_len = 2;
4795         tab.tbl_id = 17;
4796         tab.tbl_offset = 59;
4797         tab.tbl_width = 32;
4798         wlc_lcnphy_read_table(pi, &tab);
4799
4800         if (tableBuffer[0] > 63)
4801                 tableBuffer[0] -= 128;
4802         pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4803
4804         if (tableBuffer[1] > 63)
4805                 tableBuffer[1] -= 128;
4806         pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4807
4808         temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
4809         if (temp > 127)
4810                 temp -= 256;
4811         pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4812
4813         pi_lcn->lcnphy_Med_Low_Gain_db =
4814                 (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
4815         pi_lcn->lcnphy_Very_Low_Gain_db =
4816                 (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
4817
4818         tab.tbl_ptr = tableBuffer;
4819         tab.tbl_len = 2;
4820         tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4821         tab.tbl_offset = 28;
4822         tab.tbl_width = 32;
4823         wlc_lcnphy_read_table(pi, &tab);
4824
4825         pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4826         pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4827
4828 }
4829
4830 static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
4831 {
4832
4833         wlc_lcnphy_tbl_init(pi);
4834         wlc_lcnphy_rev0_baseband_init(pi);
4835         if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4836                 wlc_lcnphy_rev2_baseband_init(pi);
4837         wlc_lcnphy_bu_tweaks(pi);
4838 }
4839
4840 void wlc_phy_init_lcnphy(struct brcms_phy *pi)
4841 {
4842         u8 phybw40;
4843         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4844         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4845
4846         pi_lcn->lcnphy_cal_counter = 0;
4847         pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
4848
4849         or_phy_reg(pi, 0x44a, 0x80);
4850         and_phy_reg(pi, 0x44a, 0x7f);
4851
4852         wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
4853
4854         write_phy_reg(pi, 0x60a, 160);
4855
4856         write_phy_reg(pi, 0x46a, 25);
4857
4858         wlc_lcnphy_baseband_init(pi);
4859
4860         wlc_lcnphy_radio_init(pi);
4861
4862         if (CHSPEC_IS2G(pi->radio_chanspec))
4863                 wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
4864
4865         wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
4866
4867         si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
4868
4869         si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
4870
4871         if ((pi->sh->boardflags & BFL_FEM)
4872             && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4873                 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
4874
4875         wlc_lcnphy_agc_temp_init(pi);
4876
4877         wlc_lcnphy_temp_adj(pi);
4878
4879         mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4880
4881         udelay(100);
4882         mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4883
4884         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
4885         pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
4886         wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
4887 }
4888
4889 static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
4890 {
4891         s8 txpwr = 0;
4892         int i;
4893         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4894         struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
4895
4896         if (CHSPEC_IS2G(pi->radio_chanspec)) {
4897                 u16 cckpo = 0;
4898                 u32 offset_ofdm, offset_mcs;
4899
4900                 pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
4901
4902                 pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
4903
4904                 pi->txpa_2g[0] = sprom->pa0b0;
4905                 pi->txpa_2g[1] = sprom->pa0b1;
4906                 pi->txpa_2g[2] = sprom->pa0b2;
4907
4908                 pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
4909                 pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
4910                 pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
4911
4912                 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4913                 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4914                 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4915
4916                 pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
4917                 pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
4918                 pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
4919
4920                 txpwr = sprom->core_pwr_info[0].maxpwr_2g;
4921                 pi->tx_srom_max_2g = txpwr;
4922
4923                 for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4924                         pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4925                         pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4926                 }
4927
4928                 cckpo = sprom->cck2gpo;
4929                 offset_ofdm = sprom->ofdm2gpo;
4930                 if (cckpo) {
4931                         uint max_pwr_chan = txpwr;
4932
4933                         for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4934                                 pi->tx_srom_max_rate_2g[i] =
4935                                         max_pwr_chan - ((cckpo & 0xf) * 2);
4936                                 cckpo >>= 4;
4937                         }
4938
4939                         for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4940                                 pi->tx_srom_max_rate_2g[i] =
4941                                         max_pwr_chan -
4942                                         ((offset_ofdm & 0xf) * 2);
4943                                 offset_ofdm >>= 4;
4944                         }
4945                 } else {
4946                         u8 opo = 0;
4947
4948                         opo = sprom->opo;
4949
4950                         for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
4951                                 pi->tx_srom_max_rate_2g[i] = txpwr;
4952
4953                         for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4954                                 pi->tx_srom_max_rate_2g[i] = txpwr -
4955                                                 ((offset_ofdm & 0xf) * 2);
4956                                 offset_ofdm >>= 4;
4957                         }
4958                         offset_mcs = sprom->mcs2gpo[1] << 16;
4959                         offset_mcs |= sprom->mcs2gpo[0];
4960                         pi_lcn->lcnphy_mcs20_po = offset_mcs;
4961                         for (i = TXP_FIRST_SISO_MCS_20;
4962                              i <= TXP_LAST_SISO_MCS_20; i++) {
4963                                 pi->tx_srom_max_rate_2g[i] =
4964                                         txpwr - ((offset_mcs & 0xf) * 2);
4965                                 offset_mcs >>= 4;
4966                         }
4967                 }
4968
4969                 pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
4970                 pi_lcn->lcnphy_measPower = sprom->measpower;
4971                 pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
4972                 pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
4973                 pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
4974                 pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
4975                 pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
4976                 pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
4977                 if (sprom->ant_available_bg > 1)
4978                         wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
4979                                 sprom->ant_available_bg);
4980         }
4981         pi_lcn->lcnphy_cck_dig_filt_type = -1;
4982
4983         return true;
4984 }
4985
4986 void wlc_2064_vco_cal(struct brcms_phy *pi)
4987 {
4988         u8 calnrst;
4989
4990         mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4991         calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4992         write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4993         udelay(1);
4994         write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4995         udelay(1);
4996         write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4997         udelay(300);
4998         mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4999 }
5000
5001 bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
5002 {
5003         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
5004                 return 0;
5005         else
5006                 return (LCNPHY_TX_PWR_CTRL_HW ==
5007                         wlc_lcnphy_get_tx_pwr_ctrl((pi)));
5008 }
5009
5010 void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
5011 {
5012         u16 pwr_ctrl;
5013         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5014                 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5015         } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
5016                 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
5017                 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
5018                 wlc_lcnphy_txpower_recalc_target(pi);
5019                 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5020         }
5021 }
5022
5023 void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
5024 {
5025         u8 channel = CHSPEC_CHANNEL(chanspec);
5026
5027         wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec);
5028
5029         wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
5030
5031         or_phy_reg(pi, 0x44a, 0x44);
5032         write_phy_reg(pi, 0x44a, 0x80);
5033
5034         wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
5035         udelay(1000);
5036
5037         wlc_lcnphy_toggle_afe_pwdn(pi);
5038
5039         write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
5040         write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
5041
5042         if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
5043                 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
5044
5045                 wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
5046         } else {
5047                 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
5048
5049                 wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
5050         }
5051
5052         if (pi->sh->boardflags & BFL_FEM)
5053                 wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
5054         else
5055                 wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
5056
5057         mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
5058         wlc_lcnphy_tssi_setup(pi);
5059 }
5060
5061 void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
5062 {
5063         kfree(pi->u.pi_lcnphy);
5064 }
5065
5066 bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
5067 {
5068         struct brcms_phy_lcnphy *pi_lcn;
5069
5070         pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
5071         if (pi->u.pi_lcnphy == NULL)
5072                 return false;
5073
5074         pi_lcn = pi->u.pi_lcnphy;
5075
5076         if (0 == (pi->sh->boardflags & BFL_NOPA)) {
5077                 pi->hwpwrctrl = true;
5078                 pi->hwpwrctrl_capable = true;
5079         }
5080
5081         pi->xtalfreq = si_pmu_alp_clock(pi->sh->sih);
5082         pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5083
5084         pi->pi_fptr.init = wlc_phy_init_lcnphy;
5085         pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5086         pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5087         pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5088         pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5089         pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5090         pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5091         pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5092         pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5093
5094         if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5095                 return false;
5096
5097         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5098                 if (pi_lcn->lcnphy_tempsense_option == 3) {
5099                         pi->hwpwrctrl = true;
5100                         pi->hwpwrctrl_capable = true;
5101                         pi->temppwrctrl_capable = false;
5102                 } else {
5103                         pi->hwpwrctrl = false;
5104                         pi->hwpwrctrl_capable = false;
5105                         pi->temppwrctrl_capable = true;
5106                 }
5107         }
5108
5109         return true;
5110 }
5111
5112 static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
5113 {
5114         u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5115
5116         trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5117         ext_lna = (u16) (gain >> 29) & 0x01;
5118         lna1 = (u16) (gain >> 0) & 0x0f;
5119         lna2 = (u16) (gain >> 4) & 0x0f;
5120         tia = (u16) (gain >> 8) & 0xf;
5121         biq0 = (u16) (gain >> 12) & 0xf;
5122         biq1 = (u16) (gain >> 16) & 0xf;
5123
5124         gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5125                           ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5126                           ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5127         gain16_19 = biq1;
5128
5129         mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5130         mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5131         mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5132         mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5133         mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5134
5135         if (CHSPEC_IS2G(pi->radio_chanspec)) {
5136                 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5137                 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5138         }
5139         wlc_lcnphy_rx_gain_override_enable(pi, true);
5140 }
5141
5142 static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
5143 {
5144         u32 received_power = 0;
5145         s32 max_index = 0;
5146         u32 gain_code = 0;
5147         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5148
5149         max_index = 36;
5150         if (*gain_index >= 0)
5151                 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5152
5153         if (-1 == *gain_index) {
5154                 *gain_index = 0;
5155                 while ((*gain_index <= (s32) max_index)
5156                        && (received_power < 700)) {
5157                         wlc_lcnphy_set_rx_gain(pi,
5158                                                lcnphy_23bitgaincode_table
5159                                                [*gain_index]);
5160                         received_power =
5161                                 wlc_lcnphy_measure_digital_power(
5162                                         pi,
5163                                         pi_lcn->
5164                                         lcnphy_noise_samples);
5165                         (*gain_index)++;
5166                 }
5167                 (*gain_index)--;
5168         } else {
5169                 wlc_lcnphy_set_rx_gain(pi, gain_code);
5170                 received_power =
5171                         wlc_lcnphy_measure_digital_power(pi,
5172                                                          pi_lcn->
5173                                                          lcnphy_noise_samples);
5174         }
5175
5176         return received_power;
5177 }
5178
5179 s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
5180 {
5181         s32 gain = 0;
5182         s32 nominal_power_db;
5183         s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5184             input_power_db;
5185         s32 received_power, temperature;
5186         u32 power;
5187         u32 msb1, msb2, val1, val2, diff1, diff2;
5188         uint freq;
5189         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5190
5191         received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5192
5193         gain = lcnphy_gain_table[gain_index];
5194
5195         nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5196
5197         power = (received_power * 16);
5198         msb1 = ffs(power) - 1;
5199         msb2 = msb1 + 1;
5200         val1 = 1 << msb1;
5201         val2 = 1 << msb2;
5202         diff1 = (power - val1);
5203         diff2 = (val2 - power);
5204         if (diff1 < diff2)
5205                 log_val = msb1;
5206         else
5207                 log_val = msb2;
5208
5209         log_val = log_val * 3;
5210
5211         gain_mismatch = (nominal_power_db / 2) - (log_val);
5212
5213         desired_gain = gain + gain_mismatch;
5214
5215         input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5216
5217         if (input_power_offset_db > 127)
5218                 input_power_offset_db -= 256;
5219
5220         input_power_db = input_power_offset_db - desired_gain;
5221
5222         input_power_db =
5223                 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5224
5225         freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5226         if ((freq > 2427) && (freq <= 2467))
5227                 input_power_db = input_power_db - 1;
5228
5229         temperature = pi_lcn->lcnphy_lastsensed_temperature;
5230
5231         if ((temperature - 15) < -30)
5232                 input_power_db =
5233                         input_power_db +
5234                         (((temperature - 10 - 25) * 286) >> 12) -
5235                         7;
5236         else if ((temperature - 15) < 4)
5237                 input_power_db =
5238                         input_power_db +
5239                         (((temperature - 10 - 25) * 286) >> 12) -
5240                         3;
5241         else
5242                 input_power_db = input_power_db +
5243                                         (((temperature - 10 - 25) * 286) >> 12);
5244
5245         wlc_lcnphy_rx_gain_override_enable(pi, 0);
5246
5247         return input_power_db;
5248 }