b43legacy: move under broadcom vendor directory
[cascardo/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
1161 }
1162
1163 static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx)
1164 {
1165
1166         mod_phy_reg(pi, 0x44d,
1167                     (0x1 << 1) |
1168                     (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
1169
1170         or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
1171 }
1172
1173 static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi)
1174 {
1175
1176         and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
1177 }
1178
1179 static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b)
1180 {
1181         mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
1182
1183         mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
1184
1185         mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
1186
1187         mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
1188
1189         mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
1190
1191         mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
1192
1193 }
1194
1195 static bool
1196 wlc_lcnphy_rx_iq_est(struct brcms_phy *pi,
1197                      u16 num_samps,
1198                      u8 wait_time, struct lcnphy_iq_est *iq_est)
1199 {
1200         int wait_count = 0;
1201         bool result = true;
1202         u8 phybw40;
1203         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
1204
1205         mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
1206
1207         mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
1208
1209         mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
1210
1211         mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
1212
1213         mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
1214
1215         mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
1216
1217         while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
1218
1219                 if (wait_count > (10 * 500)) {
1220                         result = false;
1221                         goto cleanup;
1222                 }
1223                 udelay(100);
1224                 wait_count++;
1225         }
1226
1227         iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |
1228                           (u32) read_phy_reg(pi, 0x484);
1229         iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |
1230                         (u32) read_phy_reg(pi, 0x486);
1231         iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |
1232                         (u32) read_phy_reg(pi, 0x488);
1233
1234 cleanup:
1235         mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
1236
1237         mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
1238
1239         return result;
1240 }
1241
1242 static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps)
1243 {
1244 #define LCNPHY_MIN_RXIQ_PWR 2
1245         bool result;
1246         u16 a0_new, b0_new;
1247         struct lcnphy_iq_est iq_est = { 0, 0, 0 };
1248         s32 a, b, temp;
1249         s16 iq_nbits, qq_nbits, arsh, brsh;
1250         s32 iq;
1251         u32 ii, qq;
1252         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1253
1254         a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
1255         b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
1256         mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
1257
1258         mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
1259
1260         wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
1261
1262         result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
1263         if (!result)
1264                 goto cleanup;
1265
1266         iq = (s32) iq_est.iq_prod;
1267         ii = iq_est.i_pwr;
1268         qq = iq_est.q_pwr;
1269
1270         if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
1271                 result = false;
1272                 goto cleanup;
1273         }
1274
1275         iq_nbits = wlc_phy_nbits(iq);
1276         qq_nbits = wlc_phy_nbits(qq);
1277
1278         arsh = 10 - (30 - iq_nbits);
1279         if (arsh >= 0) {
1280                 a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
1281                 temp = (s32) (ii >> arsh);
1282                 if (temp == 0)
1283                         return false;
1284         } else {
1285                 a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
1286                 temp = (s32) (ii << -arsh);
1287                 if (temp == 0)
1288                         return false;
1289         }
1290         a /= temp;
1291         brsh = qq_nbits - 31 + 20;
1292         if (brsh >= 0) {
1293                 b = (qq << (31 - qq_nbits));
1294                 temp = (s32) (ii >> brsh);
1295                 if (temp == 0)
1296                         return false;
1297         } else {
1298                 b = (qq << (31 - qq_nbits));
1299                 temp = (s32) (ii << -brsh);
1300                 if (temp == 0)
1301                         return false;
1302         }
1303         b /= temp;
1304         b -= a * a;
1305         b = (s32) int_sqrt((unsigned long) b);
1306         b -= (1 << 10);
1307         a0_new = (u16) (a & 0x3ff);
1308         b0_new = (u16) (b & 0x3ff);
1309 cleanup:
1310
1311         wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
1312
1313         mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
1314
1315         mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
1316
1317         pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
1318         pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
1319
1320         return result;
1321 }
1322
1323 static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
1324 {
1325         struct lcnphy_iq_est iq_est = { 0, 0, 0 };
1326
1327         if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))
1328                 return 0;
1329         return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
1330 }
1331
1332 static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,
1333                                       u16 tia_gain, u16 lna2_gain)
1334 {
1335         u32 i_thresh_l, q_thresh_l;
1336         u32 i_thresh_h, q_thresh_h;
1337         struct lcnphy_iq_est iq_est_h, iq_est_l;
1338
1339         wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain,
1340                                                lna2_gain, 0);
1341
1342         wlc_lcnphy_rx_gain_override_enable(pi, true);
1343         wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);
1344         udelay(500);
1345         write_radio_reg(pi, RADIO_2064_REG112, 0);
1346         if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))
1347                 return false;
1348
1349         wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);
1350         udelay(500);
1351         write_radio_reg(pi, RADIO_2064_REG112, 0);
1352         if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))
1353                 return false;
1354
1355         i_thresh_l = (iq_est_l.i_pwr << 1);
1356         i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr;
1357
1358         q_thresh_l = (iq_est_l.q_pwr << 1);
1359         q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr;
1360         if ((iq_est_h.i_pwr > i_thresh_l) &&
1361             (iq_est_h.i_pwr < i_thresh_h) &&
1362             (iq_est_h.q_pwr > q_thresh_l) &&
1363             (iq_est_h.q_pwr < q_thresh_h))
1364                 return true;
1365
1366         return false;
1367 }
1368
1369 static bool
1370 wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
1371                      const struct lcnphy_rx_iqcomp *iqcomp,
1372                      int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
1373                      int tx_gain_idx)
1374 {
1375         struct lcnphy_txgains old_gains;
1376         u16 tx_pwr_ctrl;
1377         u8 tx_gain_index_old = 0;
1378         bool result = false, tx_gain_override_old = false;
1379         u16 i, Core1TxControl_old, RFOverride0_old,
1380             RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
1381             rfoverride3_old, rfoverride3val_old, rfoverride4_old,
1382             rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
1383         int tia_gain, lna2_gain, biq1_gain;
1384         bool set_gain;
1385         u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
1386         u16 values_to_save[11];
1387         s16 *ptr;
1388         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1389
1390         ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
1391         if (NULL == ptr)
1392                 return false;
1393         if (module == 2) {
1394                 while (iqcomp_sz--) {
1395                         if (iqcomp[iqcomp_sz].chan ==
1396                             CHSPEC_CHANNEL(pi->radio_chanspec)) {
1397                                 wlc_lcnphy_set_rx_iq_comp(pi,
1398                                                           (u16)
1399                                                           iqcomp[iqcomp_sz].a,
1400                                                           (u16)
1401                                                           iqcomp[iqcomp_sz].b);
1402                                 result = true;
1403                                 break;
1404                         }
1405                 }
1406                 goto cal_done;
1407         }
1408
1409         WARN_ON(module != 1);
1410         tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1411         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1412
1413         for (i = 0; i < 11; i++)
1414                 values_to_save[i] =
1415                         read_radio_reg(pi, rxiq_cal_rf_reg[i]);
1416         Core1TxControl_old = read_phy_reg(pi, 0x631);
1417
1418         or_phy_reg(pi, 0x631, 0x0015);
1419
1420         RFOverride0_old = read_phy_reg(pi, 0x44c);
1421         RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
1422         rfoverride2_old = read_phy_reg(pi, 0x4b0);
1423         rfoverride2val_old = read_phy_reg(pi, 0x4b1);
1424         rfoverride3_old = read_phy_reg(pi, 0x4f9);
1425         rfoverride3val_old = read_phy_reg(pi, 0x4fa);
1426         rfoverride4_old = read_phy_reg(pi, 0x938);
1427         rfoverride4val_old = read_phy_reg(pi, 0x939);
1428         afectrlovr_old = read_phy_reg(pi, 0x43b);
1429         afectrlovrval_old = read_phy_reg(pi, 0x43c);
1430         old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1431         old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1432
1433         tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1434         if (tx_gain_override_old) {
1435                 wlc_lcnphy_get_tx_gain(pi, &old_gains);
1436                 tx_gain_index_old = pi_lcn->lcnphy_current_index;
1437         }
1438
1439         wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
1440
1441         mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
1442         mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
1443
1444         mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
1445         mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
1446
1447         write_radio_reg(pi, RADIO_2064_REG116, 0x06);
1448         write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
1449         write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
1450         write_radio_reg(pi, RADIO_2064_REG098, 0x03);
1451         write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
1452         mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
1453         write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
1454         write_radio_reg(pi, RADIO_2064_REG114, 0x01);
1455         write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
1456         write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
1457
1458         mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
1459         mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
1460         mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
1461         mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
1462         mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
1463         mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
1464         mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
1465         mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
1466         mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
1467         mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
1468
1469         mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
1470         mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
1471
1472         write_phy_reg(pi, 0x6da, 0xffff);
1473         or_phy_reg(pi, 0x6db, 0x3);
1474
1475         wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
1476         for (lna2_gain = 3; lna2_gain >= 0; lna2_gain--) {
1477                 for (tia_gain = 4; tia_gain >= 0; tia_gain--) {
1478                         for (biq1_gain = 6; biq1_gain >= 0; biq1_gain--) {
1479                                 set_gain = wlc_lcnphy_rx_iq_cal_gain(pi,
1480                                                                      (u16)
1481                                                                      biq1_gain,
1482                                                                      (u16)
1483                                                                      tia_gain,
1484                                                                      (u16)
1485                                                                      lna2_gain);
1486                                 if (!set_gain)
1487                                         continue;
1488
1489                                 result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024);
1490                                 goto stop_tone;
1491                         }
1492                 }
1493         }
1494
1495 stop_tone:
1496         wlc_lcnphy_stop_tx_tone(pi);
1497
1498         write_phy_reg(pi, 0x631, Core1TxControl_old);
1499
1500         write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
1501         write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
1502         write_phy_reg(pi, 0x4b0, rfoverride2_old);
1503         write_phy_reg(pi, 0x4b1, rfoverride2val_old);
1504         write_phy_reg(pi, 0x4f9, rfoverride3_old);
1505         write_phy_reg(pi, 0x4fa, rfoverride3val_old);
1506         write_phy_reg(pi, 0x938, rfoverride4_old);
1507         write_phy_reg(pi, 0x939, rfoverride4val_old);
1508         write_phy_reg(pi, 0x43b, afectrlovr_old);
1509         write_phy_reg(pi, 0x43c, afectrlovrval_old);
1510         write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
1511         write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
1512
1513         wlc_lcnphy_clear_trsw_override(pi);
1514
1515         mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
1516
1517         for (i = 0; i < 11; i++)
1518                 write_radio_reg(pi, rxiq_cal_rf_reg[i],
1519                                 values_to_save[i]);
1520
1521         if (tx_gain_override_old)
1522                 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
1523         else
1524                 wlc_lcnphy_disable_tx_gain_override(pi);
1525
1526         wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
1527         wlc_lcnphy_rx_gain_override_enable(pi, false);
1528
1529 cal_done:
1530         kfree(ptr);
1531         return result;
1532 }
1533
1534 s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi)
1535 {
1536         s8 index;
1537         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1538
1539         if (txpwrctrl_off(pi))
1540                 index = pi_lcn->lcnphy_current_index;
1541         else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1542                 index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(
1543                               pi) / 2);
1544         else
1545                 index = pi_lcn->lcnphy_current_index;
1546         return index;
1547 }
1548
1549 void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel)
1550 {
1551         u16 afectrlovr, afectrlovrval;
1552         afectrlovr = read_phy_reg(pi, 0x43b);
1553         afectrlovrval = read_phy_reg(pi, 0x43c);
1554         if (channel != 0) {
1555                 mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
1556
1557                 mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1558
1559                 mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1560
1561                 mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1562
1563                 write_phy_reg(pi, 0x44b, 0xffff);
1564                 wlc_lcnphy_tx_pu(pi, 1);
1565
1566                 mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1567
1568                 or_phy_reg(pi, 0x6da, 0x0080);
1569
1570                 or_phy_reg(pi, 0x00a, 0x228);
1571         } else {
1572                 and_phy_reg(pi, 0x00a, ~(0x228));
1573
1574                 and_phy_reg(pi, 0x6da, 0xFF7F);
1575                 write_phy_reg(pi, 0x43b, afectrlovr);
1576                 write_phy_reg(pi, 0x43c, afectrlovrval);
1577         }
1578 }
1579
1580 static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi)
1581 {
1582         u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
1583
1584         save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1585         save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1586
1587         write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1588         write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1589
1590         write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1591         write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1592
1593         write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1594         write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1595 }
1596
1597 static void
1598 wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable)
1599 {
1600         if (enable) {
1601                 write_phy_reg(pi, 0x942, 0x7);
1602                 write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
1603                 write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
1604
1605                 write_phy_reg(pi, 0x44a, 0x084);
1606                 write_phy_reg(pi, 0x44a, 0x080);
1607                 write_phy_reg(pi, 0x6d3, 0x2222);
1608                 write_phy_reg(pi, 0x6d3, 0x2220);
1609         } else {
1610                 write_phy_reg(pi, 0x942, 0x0);
1611                 write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
1612                 write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
1613         }
1614         wlapi_switch_macfreq(pi->sh->physhim, enable);
1615 }
1616
1617 static void
1618 wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
1619 {
1620         u8 channel = CHSPEC_CHANNEL(chanspec);
1621         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1622
1623         if (channel == 14)
1624                 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1625         else
1626                 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1627
1628         pi_lcn->lcnphy_bandedge_corr = 2;
1629         if (channel == 1)
1630                 pi_lcn->lcnphy_bandedge_corr = 4;
1631
1632         if (channel == 1 || channel == 2 || channel == 3 ||
1633             channel == 4 || channel == 9 ||
1634             channel == 10 || channel == 11 || channel == 12) {
1635                 bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
1636                                       0x03000c04);
1637                 bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
1638                                         ~0x00ffffff, 0x0);
1639                 bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
1640                                       0x200005c0);
1641
1642                 bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
1643                               BCMA_CC_PMU_CTL_PLL_UPD);
1644                 write_phy_reg(pi, 0x942, 0);
1645                 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
1646                 pi_lcn->lcnphy_spurmod = false;
1647                 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
1648
1649                 write_phy_reg(pi, 0x425, 0x5907);
1650         } else {
1651                 bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
1652                                       0x03140c04);
1653                 bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
1654                                         ~0x00ffffff, 0x333333);
1655                 bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
1656                                       0x202c2820);
1657
1658                 bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
1659                               BCMA_CC_PMU_CTL_PLL_UPD);
1660                 write_phy_reg(pi, 0x942, 0);
1661                 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
1662
1663                 pi_lcn->lcnphy_spurmod = false;
1664                 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
1665
1666                 write_phy_reg(pi, 0x425, 0x590a);
1667         }
1668
1669         or_phy_reg(pi, 0x44a, 0x44);
1670         write_phy_reg(pi, 0x44a, 0x80);
1671 }
1672
1673 static void
1674 wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
1675 {
1676         uint i;
1677         const struct chan_info_2064_lcnphy *ci;
1678         u8 rfpll_doubler = 0;
1679         u8 pll_pwrup, pll_pwrup_ovr;
1680         s32 qFxtal, qFref, qFvco, qFcal;
1681         u8 d15, d16, f16, e44, e45;
1682         u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
1683         u16 loop_bw, d30, setCount;
1684
1685         u8 h29, h28_ten, e30, h30_ten, cp_current;
1686         u16 g30, d28;
1687
1688         ci = &chan_info_2064_lcnphy[0];
1689         rfpll_doubler = 1;
1690
1691         mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
1692
1693         write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
1694         if (!rfpll_doubler) {
1695                 loop_bw = PLL_2064_LOOP_BW;
1696                 d30 = PLL_2064_D30;
1697         } else {
1698                 loop_bw = PLL_2064_LOOP_BW_DOUBLER;
1699                 d30 = PLL_2064_D30_DOUBLER;
1700         }
1701
1702         if (CHSPEC_IS2G(pi->radio_chanspec)) {
1703                 for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)
1704                         if (chan_info_2064_lcnphy[i].chan == channel)
1705                                 break;
1706
1707                 if (i >= ARRAY_SIZE(chan_info_2064_lcnphy))
1708                         return;
1709
1710                 ci = &chan_info_2064_lcnphy[i];
1711         }
1712
1713         write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
1714
1715         mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
1716
1717         mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
1718
1719         mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
1720
1721         mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
1722                       (ci->logen_rccr_rx) << 2);
1723
1724         mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
1725
1726         mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
1727                       (ci->pa_rxrf_lna2_freq_tune) << 4);
1728
1729         write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
1730
1731         pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
1732         pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
1733
1734         or_radio_reg(pi, RADIO_2064_REG044, 0x07);
1735
1736         or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
1737         e44 = 0;
1738         e45 = 0;
1739
1740         fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
1741         if (pi->xtalfreq > 26000000)
1742                 e44 = 1;
1743         if (pi->xtalfreq > 52000000)
1744                 e45 = 1;
1745         if (e44 == 0)
1746                 fcal_div = 1;
1747         else if (e45 == 0)
1748                 fcal_div = 2;
1749         else
1750                 fcal_div = 4;
1751         fvco3 = (ci->freq * 3);
1752         fref3 = 2 * fpfd;
1753
1754         qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
1755         qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
1756         qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
1757         qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
1758
1759         write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
1760
1761         d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
1762         write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
1763         write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
1764
1765         d16 = (qFcal * 8 / (d15 + 1)) - 1;
1766         write_radio_reg(pi, RADIO_2064_REG051, d16);
1767
1768         f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
1769         setCount = f16 * 3 * (ci->freq) / 32 - 1;
1770         mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
1771                       (u8) (setCount >> 8));
1772
1773         or_radio_reg(pi, RADIO_2064_REG053, 0x10);
1774         write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
1775
1776         div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
1777
1778         div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
1779         while (div_frac >= fref3) {
1780                 div_int++;
1781                 div_frac -= fref3;
1782         }
1783         div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
1784
1785         mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
1786                       (u8) (div_int >> 4));
1787         mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
1788                       (u8) (div_int << 4));
1789         mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
1790                       (u8) (div_frac >> 16));
1791         write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
1792         write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
1793
1794         write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
1795
1796         write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
1797         write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
1798         write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
1799
1800         h29 = LCN_BW_LMT / loop_bw;
1801         d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
1802                 (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
1803                (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
1804               + PLL_2064_LOW_END_KVCO;
1805         h28_ten = (d28 * 10) / LCN_VCO_DIV;
1806         e30 = (d30 - LCN_OFFSET) / LCN_FACT;
1807         g30 = LCN_OFFSET + (e30 * LCN_FACT);
1808         h30_ten = (g30 * 10) / LCN_CUR_DIV;
1809         cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten;
1810         mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
1811
1812         if (channel >= 1 && channel <= 5)
1813                 write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
1814         else
1815                 write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
1816         write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
1817
1818         mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
1819         udelay(1);
1820
1821         wlc_2064_vco_cal(pi);
1822
1823         write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
1824         write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
1825         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
1826                 write_radio_reg(pi, RADIO_2064_REG038, 3);
1827                 write_radio_reg(pi, RADIO_2064_REG091, 7);
1828         }
1829
1830         if (!(pi->sh->boardflags & BFL_FEM)) {
1831                 static const u8 reg038[14] = {
1832                         0xd, 0xe, 0xd, 0xd, 0xd, 0xc, 0xa,
1833                         0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0
1834                 };
1835
1836                 write_radio_reg(pi, RADIO_2064_REG02A, 0xf);
1837                 write_radio_reg(pi, RADIO_2064_REG091, 0x3);
1838                 write_radio_reg(pi, RADIO_2064_REG038, 0x3);
1839
1840                 write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]);
1841         }
1842 }
1843
1844 static int
1845 wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type)
1846 {
1847         s16 filt_index = -1;
1848         int j;
1849
1850         u16 addr[] = {
1851                 0x910,
1852                 0x91e,
1853                 0x91f,
1854                 0x924,
1855                 0x925,
1856                 0x926,
1857                 0x920,
1858                 0x921,
1859                 0x927,
1860                 0x928,
1861                 0x929,
1862                 0x922,
1863                 0x923,
1864                 0x930,
1865                 0x931,
1866                 0x932
1867         };
1868
1869         u16 addr_ofdm[] = {
1870                 0x90f,
1871                 0x900,
1872                 0x901,
1873                 0x906,
1874                 0x907,
1875                 0x908,
1876                 0x902,
1877                 0x903,
1878                 0x909,
1879                 0x90a,
1880                 0x90b,
1881                 0x904,
1882                 0x905,
1883                 0x90c,
1884                 0x90d,
1885                 0x90e
1886         };
1887
1888         if (!is_ofdm) {
1889                 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
1890                         if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
1891                                 filt_index = (s16) j;
1892                                 break;
1893                         }
1894                 }
1895
1896                 if (filt_index != -1) {
1897                         for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1898                                 write_phy_reg(pi, addr[j],
1899                                               LCNPHY_txdigfiltcoeffs_cck
1900                                               [filt_index][j + 1]);
1901                 }
1902         } else {
1903                 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
1904                         if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
1905                                 filt_index = (s16) j;
1906                                 break;
1907                         }
1908                 }
1909
1910                 if (filt_index != -1) {
1911                         for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1912                                 write_phy_reg(pi, addr_ofdm[j],
1913                                               LCNPHY_txdigfiltcoeffs_ofdm
1914                                               [filt_index][j + 1]);
1915                 }
1916         }
1917
1918         return (filt_index != -1) ? 0 : -1;
1919 }
1920
1921 static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi)
1922 {
1923         u16 pa_gain;
1924
1925         pa_gain = (read_phy_reg(pi, 0x4fb) &
1926                    LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1927                   LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1928
1929         return pa_gain;
1930 }
1931
1932 static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,
1933                                    struct lcnphy_txgains *target_gains)
1934 {
1935         u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1936
1937         mod_phy_reg(
1938                 pi, 0x4b5,
1939                 (0xffff << 0),
1940                 ((target_gains->gm_gain) |
1941                  (target_gains->pga_gain << 8)) <<
1942                 0);
1943         mod_phy_reg(pi, 0x4fb,
1944                     (0x7fff << 0),
1945                     ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1946
1947         mod_phy_reg(
1948                 pi, 0x4fc,
1949                 (0xffff << 0),
1950                 ((target_gains->gm_gain) |
1951                  (target_gains->pga_gain << 8)) <<
1952                 0);
1953         mod_phy_reg(pi, 0x4fd,
1954                     (0x7fff << 0),
1955                     ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1956
1957         wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1958
1959         wlc_lcnphy_enable_tx_gain_override(pi);
1960 }
1961
1962 static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi)
1963 {
1964         u16 m0m1;
1965         struct phytbl_info tab;
1966
1967         tab.tbl_ptr = &m0m1;
1968         tab.tbl_len = 1;
1969         tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1970         tab.tbl_offset = 87;
1971         tab.tbl_width = 16;
1972         wlc_lcnphy_read_table(pi, &tab);
1973
1974         return (u8) ((m0m1 & 0xff00) >> 8);
1975 }
1976
1977 static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0)
1978 {
1979         u16 m0m1 = (u16) m0 << 8;
1980         struct phytbl_info tab;
1981
1982         tab.tbl_ptr = &m0m1;
1983         tab.tbl_len = 1;
1984         tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1985         tab.tbl_offset = 87;
1986         tab.tbl_width = 16;
1987         wlc_lcnphy_write_table(pi, &tab);
1988 }
1989
1990 static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi)
1991 {
1992         u32 data_buf[64];
1993         struct phytbl_info tab;
1994
1995         memset(data_buf, 0, sizeof(data_buf));
1996
1997         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1998         tab.tbl_width = 32;
1999         tab.tbl_ptr = data_buf;
2000
2001         if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
2002
2003                 tab.tbl_len = 30;
2004                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2005                 wlc_lcnphy_write_table(pi, &tab);
2006         }
2007
2008         tab.tbl_len = 64;
2009         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
2010         wlc_lcnphy_write_table(pi, &tab);
2011 }
2012
2013 enum lcnphy_tssi_mode {
2014         LCNPHY_TSSI_PRE_PA,
2015         LCNPHY_TSSI_POST_PA,
2016         LCNPHY_TSSI_EXT
2017 };
2018
2019 static void
2020 wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
2021 {
2022         mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
2023
2024         mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
2025
2026         if (LCNPHY_TSSI_POST_PA == pos) {
2027                 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
2028
2029                 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
2030
2031                 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2032                         mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2033                 } else {
2034                         mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
2035                         mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2036                         mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0);
2037                         mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2);
2038                         mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0);
2039                         mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4);
2040                         mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
2041                         mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77);
2042                         mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1);
2043                         mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7);
2044                         mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1);
2045                         mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4);
2046                 }
2047         } else {
2048                 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
2049
2050                 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
2051
2052                 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2053                         mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2054                 } else {
2055                         mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2056                         mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2057                 }
2058         }
2059         mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
2060
2061         if (LCNPHY_TSSI_EXT == pos) {
2062                 write_radio_reg(pi, RADIO_2064_REG07F, 1);
2063                 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
2064                 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
2065                 mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
2066         }
2067 }
2068
2069 static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi)
2070 {
2071         u16 N1, N2, N3, N4, N5, N6, N;
2072         N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
2073               >> 0);
2074         N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
2075                    >> 12);
2076         N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
2077               >> 0);
2078         N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
2079                    >> 8);
2080         N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
2081               >> 0);
2082         N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
2083                    >> 8);
2084         N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
2085         if (N < 1600)
2086                 N = 1600;
2087         return N;
2088 }
2089
2090 static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
2091 {
2092         u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
2093         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2094
2095         auxpga_vmid = (2 << 8) |
2096                       (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
2097         auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
2098         auxpga_gain_temp = 2;
2099
2100         mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
2101
2102         mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
2103
2104         mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
2105
2106         mod_phy_reg(pi, 0x4db,
2107                     (0x3ff << 0) |
2108                     (0x7 << 12),
2109                     (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2110
2111         mod_phy_reg(pi, 0x4dc,
2112                     (0x3ff << 0) |
2113                     (0x7 << 12),
2114                     (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2115
2116         mod_phy_reg(pi, 0x40a,
2117                     (0x3ff << 0) |
2118                     (0x7 << 12),
2119                     (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2120
2121         mod_phy_reg(pi, 0x40b,
2122                     (0x3ff << 0) |
2123                     (0x7 << 12),
2124                     (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2125
2126         mod_phy_reg(pi, 0x40c,
2127                     (0x3ff << 0) |
2128                     (0x7 << 12),
2129                     (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2130
2131         mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
2132         mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0));
2133 }
2134
2135 static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
2136 {
2137         struct phytbl_info tab;
2138         u32 rfseq, ind;
2139         enum lcnphy_tssi_mode mode;
2140         u8 tssi_sel;
2141
2142         if (pi->sh->boardflags & BFL_FEM) {
2143                 tssi_sel = 0x1;
2144                 mode = LCNPHY_TSSI_EXT;
2145         } else {
2146                 tssi_sel = 0xe;
2147                 mode = LCNPHY_TSSI_POST_PA;
2148         }
2149         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2150         tab.tbl_width = 32;
2151         tab.tbl_ptr = &ind;
2152         tab.tbl_len = 1;
2153         tab.tbl_offset = 0;
2154         for (ind = 0; ind < 128; ind++) {
2155                 wlc_lcnphy_write_table(pi, &tab);
2156                 tab.tbl_offset++;
2157         }
2158         tab.tbl_offset = 704;
2159         for (ind = 0; ind < 128; ind++) {
2160                 wlc_lcnphy_write_table(pi, &tab);
2161                 tab.tbl_offset++;
2162         }
2163         mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2164
2165         mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2166
2167         mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
2168
2169         wlc_lcnphy_set_tssi_mux(pi, mode);
2170         mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2171
2172         mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
2173
2174         mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2175
2176         mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
2177
2178         mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2179
2180         mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2181
2182         mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2183
2184         mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2185
2186         mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
2187
2188         mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2189
2190         mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
2191
2192         mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
2193
2194         mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
2195
2196         wlc_lcnphy_clear_tx_power_offsets(pi);
2197
2198         mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2199
2200         mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
2201
2202         mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
2203
2204         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2205                 mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel);
2206                 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2207         } else {
2208                 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1);
2209                 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2210                 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
2211         }
2212
2213         write_radio_reg(pi, RADIO_2064_REG025, 0xc);
2214
2215         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2216                 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2217         } else {
2218                 if (CHSPEC_IS2G(pi->radio_chanspec))
2219                         mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2220                 else
2221                         mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
2222         }
2223
2224         if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2225                 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2226         else
2227                 mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
2228
2229         mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
2230
2231         mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
2232
2233         if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2234                 mod_phy_reg(pi, 0x4d7,
2235                             (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
2236
2237         rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2238         tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2239         tab.tbl_width = 16;
2240         tab.tbl_ptr = &rfseq;
2241         tab.tbl_len = 1;
2242         tab.tbl_offset = 6;
2243         wlc_lcnphy_write_table(pi, &tab);
2244
2245         mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2246
2247         mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2248
2249         mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2250
2251         mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
2252
2253         mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
2254
2255         mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0);
2256         mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
2257         mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2258
2259         wlc_lcnphy_pwrctrl_rssiparams(pi);
2260 }
2261
2262 void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi)
2263 {
2264         u16 tx_cnt, tx_total, npt;
2265         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2266
2267         tx_total = wlc_lcnphy_total_tx_frames(pi);
2268         tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
2269         npt = wlc_lcnphy_get_tx_pwr_npt(pi);
2270
2271         if (tx_cnt > (1 << npt)) {
2272
2273                 pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
2274
2275                 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2276                 pi_lcn->lcnphy_tssi_npt = npt;
2277
2278         }
2279 }
2280
2281 s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)
2282 {
2283         s32 a, b, p;
2284
2285         a = 32768 + (a1 * tssi);
2286         b = (1024 * b0) + (64 * b1 * tssi);
2287         p = ((2 * b) + a) / (2 * a);
2288
2289         return p;
2290 }
2291
2292 static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi)
2293 {
2294         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2295         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2296                 return;
2297
2298         pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
2299         pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
2300 }
2301
2302 void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi)
2303 {
2304         struct phytbl_info tab;
2305         u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM +
2306                        BRCMS_NUM_RATES_MCS_1_STREAM];
2307         uint i, j;
2308         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2309                 return;
2310
2311         for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {
2312
2313                 if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM)
2314                         j = TXP_FIRST_MCS_20_SISO;
2315
2316                 rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));
2317         }
2318
2319         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2320         tab.tbl_width = 32;
2321         tab.tbl_len = ARRAY_SIZE(rate_table);
2322         tab.tbl_ptr = rate_table;
2323         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2324         wlc_lcnphy_write_table(pi, &tab);
2325
2326         if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
2327                 wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
2328
2329                 wlc_lcnphy_txpower_reset_npt(pi);
2330         }
2331 }
2332
2333 static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index)
2334 {
2335         u32 cck_offset[4] = { 22, 22, 22, 22 };
2336         u32 ofdm_offset, reg_offset_cck;
2337         int i;
2338         u16 index2;
2339         struct phytbl_info tab;
2340
2341         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2342                 return;
2343
2344         mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2345
2346         mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
2347
2348         or_phy_reg(pi, 0x6da, 0x0040);
2349
2350         reg_offset_cck = 0;
2351         for (i = 0; i < 4; i++)
2352                 cck_offset[i] -= reg_offset_cck;
2353         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2354         tab.tbl_width = 32;
2355         tab.tbl_len = 4;
2356         tab.tbl_ptr = cck_offset;
2357         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2358         wlc_lcnphy_write_table(pi, &tab);
2359         ofdm_offset = 0;
2360         tab.tbl_len = 1;
2361         tab.tbl_ptr = &ofdm_offset;
2362         for (i = 836; i < 862; i++) {
2363                 tab.tbl_offset = i;
2364                 wlc_lcnphy_write_table(pi, &tab);
2365         }
2366
2367         mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
2368
2369         mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2370
2371         mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
2372
2373         mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
2374
2375         mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
2376
2377         mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
2378
2379         index2 = (u16) (index * 2);
2380         mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
2381
2382         mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
2383
2384 }
2385
2386 static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)
2387 {
2388         s8 index, delta_brd, delta_temp, new_index, tempcorrx;
2389         s16 manp, meas_temp, temp_diff;
2390         bool neg = false;
2391         u16 temp;
2392         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2393
2394         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2395                 return pi_lcn->lcnphy_current_index;
2396
2397         index = FIXED_TXPWR;
2398
2399         if (pi_lcn->lcnphy_tempsense_slope == 0)
2400                 return index;
2401
2402         temp = (u16) wlc_lcnphy_tempsense(pi, 0);
2403         meas_temp = LCNPHY_TEMPSENSE(temp);
2404
2405         if (pi->tx_power_min != 0)
2406                 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
2407         else
2408                 delta_brd = 0;
2409
2410         manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
2411         temp_diff = manp - meas_temp;
2412         if (temp_diff < 0) {
2413                 neg = true;
2414                 temp_diff = -temp_diff;
2415         }
2416
2417         delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
2418                                                   (u32) (pi_lcn->
2419                                                          lcnphy_tempsense_slope
2420                                                          * 10), 0);
2421         if (neg)
2422                 delta_temp = -delta_temp;
2423
2424         if (pi_lcn->lcnphy_tempsense_option == 3
2425             && LCNREV_IS(pi->pubpi.phy_rev, 0))
2426                 delta_temp = 0;
2427         if (pi_lcn->lcnphy_tempcorrx > 31)
2428                 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
2429         else
2430                 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
2431         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2432                 tempcorrx = 4;
2433         new_index =
2434                 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
2435         new_index += tempcorrx;
2436
2437         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2438                 index = 127;
2439
2440         if (new_index < 0 || new_index > 126)
2441                 return index;
2442
2443         return new_index;
2444 }
2445
2446 static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode)
2447 {
2448
2449         u16 current_mode = mode;
2450         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
2451             mode == LCNPHY_TX_PWR_CTRL_HW)
2452                 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
2453         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
2454             mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
2455                 current_mode = LCNPHY_TX_PWR_CTRL_HW;
2456         return current_mode;
2457 }
2458
2459 void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)
2460 {
2461         u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2462         s8 index;
2463         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2464
2465         mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
2466         old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
2467
2468         mod_phy_reg(pi, 0x6da, (0x1 << 6),
2469                     ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
2470
2471         mod_phy_reg(pi, 0x6a3, (0x1 << 4),
2472                     ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
2473
2474         if (old_mode != mode) {
2475                 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
2476
2477                         wlc_lcnphy_tx_pwr_update_npt(pi);
2478
2479                         wlc_lcnphy_clear_tx_power_offsets(pi);
2480                 }
2481                 if (LCNPHY_TX_PWR_CTRL_HW == mode) {
2482
2483                         wlc_lcnphy_txpower_recalc_target(pi);
2484
2485                         wlc_lcnphy_set_start_tx_pwr_idx(pi,
2486                                                         pi_lcn->
2487                                                         lcnphy_tssi_idx);
2488                         wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
2489                         mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
2490
2491                         pi_lcn->lcnphy_tssi_tx_cnt =
2492                                 wlc_lcnphy_total_tx_frames(pi);
2493
2494                         wlc_lcnphy_disable_tx_gain_override(pi);
2495                         pi_lcn->lcnphy_tx_power_idx_override = -1;
2496                 } else
2497                         wlc_lcnphy_enable_tx_gain_override(pi);
2498
2499                 mod_phy_reg(pi, 0x4a4,
2500                             ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
2501                 if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
2502                         index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
2503                         wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
2504                         pi_lcn->lcnphy_current_index = (s8)
2505                                                        ((read_phy_reg(pi,
2506                                                                       0x4a9) &
2507                                                          0xFF) / 2);
2508                 }
2509         }
2510 }
2511
2512 static void
2513 wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)
2514 {
2515         u16 vmid;
2516         int i;
2517         for (i = 0; i < 20; i++)
2518                 values_to_save[i] =
2519                         read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
2520
2521         mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2522         mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2523
2524         mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
2525         mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
2526
2527         mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2528         mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2529
2530         mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
2531         mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
2532
2533         if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2534                 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
2535         else
2536                 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
2537         or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
2538
2539         or_radio_reg(pi, RADIO_2064_REG036, 0x01);
2540         or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
2541         udelay(20);
2542
2543         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2544                 if (CHSPEC_IS5G(pi->radio_chanspec))
2545                         mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2546                 else
2547                         or_radio_reg(pi, RADIO_2064_REG03A, 1);
2548         } else {
2549                 if (CHSPEC_IS5G(pi->radio_chanspec))
2550                         mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
2551                 else
2552                         or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
2553         }
2554
2555         udelay(20);
2556
2557         write_radio_reg(pi, RADIO_2064_REG025, 0xF);
2558         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2559                 if (CHSPEC_IS5G(pi->radio_chanspec))
2560                         mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
2561                 else
2562                         mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
2563         } else {
2564                 if (CHSPEC_IS5G(pi->radio_chanspec))
2565                         mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
2566                 else
2567                         mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
2568         }
2569
2570         udelay(20);
2571
2572         write_radio_reg(pi, RADIO_2064_REG005, 0x8);
2573         or_radio_reg(pi, RADIO_2064_REG112, 0x80);
2574         udelay(20);
2575
2576         or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2577         or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2578         udelay(20);
2579
2580         or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
2581         or_radio_reg(pi, RADIO_2064_REG113, 0x10);
2582         udelay(20);
2583
2584         write_radio_reg(pi, RADIO_2064_REG007, 0x1);
2585         udelay(20);
2586
2587         vmid = 0x2A6;
2588         mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
2589         write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
2590         or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2591         udelay(20);
2592
2593         or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2594         udelay(20);
2595         write_radio_reg(pi, RADIO_2064_REG012, 0x02);
2596         or_radio_reg(pi, RADIO_2064_REG112, 0x06);
2597         write_radio_reg(pi, RADIO_2064_REG036, 0x11);
2598         write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
2599         write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
2600         write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
2601         write_radio_reg(pi, RADIO_2064_REG092, 0x15);
2602 }
2603
2604 static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)
2605 {
2606         uint delay_count = 0;
2607
2608         while (wlc_lcnphy_iqcal_active(pi)) {
2609                 udelay(100);
2610                 delay_count++;
2611
2612                 if (delay_count > (10 * 500))
2613                         break;
2614         }
2615
2616         return (0 == wlc_lcnphy_iqcal_active(pi));
2617 }
2618
2619 static void
2620 wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)
2621 {
2622         int i;
2623
2624         and_phy_reg(pi, 0x44c, 0x0 >> 11);
2625
2626         and_phy_reg(pi, 0x43b, 0xC);
2627
2628         for (i = 0; i < 20; i++)
2629                 write_radio_reg(pi, iqlo_loopback_rf_regs[i],
2630                                 values_to_save[i]);
2631 }
2632
2633 static void
2634 wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
2635                        struct lcnphy_txgains *target_gains,
2636                        enum lcnphy_cal_mode cal_mode, bool keep_tone)
2637 {
2638
2639         struct lcnphy_txgains cal_gains, temp_gains;
2640         u16 hash;
2641         u8 band_idx;
2642         int j;
2643         u16 ncorr_override[5];
2644         u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
2645                               0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
2646
2647         u16 commands_fullcal[] = {
2648                 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2649         };
2650
2651         u16 commands_recal[] = {
2652                 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2653         };
2654
2655         u16 command_nums_fullcal[] = {
2656                 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2657         };
2658
2659         u16 command_nums_recal[] = {
2660                 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2661         };
2662         u16 *command_nums = command_nums_fullcal;
2663
2664         u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
2665         u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
2666         u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
2667         bool tx_gain_override_old;
2668         struct lcnphy_txgains old_gains;
2669         uint i, n_cal_cmds = 0, n_cal_start = 0;
2670         u16 *values_to_save;
2671         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2672
2673         values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
2674         if (NULL == values_to_save)
2675                 return;
2676
2677         save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
2678         save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
2679
2680         or_phy_reg(pi, 0x6da, 0x40);
2681         or_phy_reg(pi, 0x6db, 0x3);
2682
2683         switch (cal_mode) {
2684         case LCNPHY_CAL_FULL:
2685                 start_coeffs = syst_coeffs;
2686                 cal_cmds = commands_fullcal;
2687                 n_cal_cmds = ARRAY_SIZE(commands_fullcal);
2688                 break;
2689
2690         case LCNPHY_CAL_RECAL:
2691                 start_coeffs = syst_coeffs;
2692                 cal_cmds = commands_recal;
2693                 n_cal_cmds = ARRAY_SIZE(commands_recal);
2694                 command_nums = command_nums_recal;
2695                 break;
2696
2697         default:
2698                 break;
2699         }
2700
2701         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2702                                       start_coeffs, 11, 16, 64);
2703
2704         write_phy_reg(pi, 0x6da, 0xffff);
2705         mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
2706
2707         tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2708
2709         mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2710
2711         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2712
2713         save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
2714
2715         mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
2716
2717         mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
2718
2719         wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
2720
2721         tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2722         if (tx_gain_override_old)
2723                 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2724
2725         if (!target_gains) {
2726                 if (!tx_gain_override_old)
2727                         wlc_lcnphy_set_tx_pwr_by_index(pi,
2728                                                        pi_lcn->lcnphy_tssi_idx);
2729                 wlc_lcnphy_get_tx_gain(pi, &temp_gains);
2730                 target_gains = &temp_gains;
2731         }
2732
2733         hash = (target_gains->gm_gain << 8) |
2734                (target_gains->pga_gain << 4) | (target_gains->pad_gain);
2735
2736         band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
2737
2738         cal_gains = *target_gains;
2739         memset(ncorr_override, 0, sizeof(ncorr_override));
2740         for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
2741                 if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
2742                         cal_gains.gm_gain =
2743                                 tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
2744                         cal_gains.pga_gain =
2745                                 tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
2746                         cal_gains.pad_gain =
2747                                 tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
2748                         memcpy(ncorr_override,
2749                                &tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
2750                                sizeof(ncorr_override));
2751                         break;
2752                 }
2753         }
2754
2755         wlc_lcnphy_set_tx_gain(pi, &cal_gains);
2756
2757         write_phy_reg(pi, 0x453, 0xaa9);
2758         write_phy_reg(pi, 0x93d, 0xc0);
2759
2760         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2761                                       lcnphy_iqcal_loft_gainladder,
2762                                       ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
2763                                       16, 0);
2764
2765         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2766                                       lcnphy_iqcal_ir_gainladder,
2767                                       ARRAY_SIZE(
2768                                               lcnphy_iqcal_ir_gainladder), 16,
2769                                       32);
2770
2771         if (pi->phy_tx_tone_freq) {
2772
2773                 wlc_lcnphy_stop_tx_tone(pi);
2774                 udelay(5);
2775                 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2776         } else {
2777                 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2778         }
2779
2780         write_phy_reg(pi, 0x6da, 0xffff);
2781
2782         for (i = n_cal_start; i < n_cal_cmds; i++) {
2783                 u16 zero_diq = 0;
2784                 u16 best_coeffs[11];
2785                 u16 command_num;
2786
2787                 cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2788
2789                 command_num = command_nums[i];
2790                 if (ncorr_override[cal_type])
2791                         command_num =
2792                                 ncorr_override[cal_type] << 8 | (command_num &
2793                                                                  0xff);
2794
2795                 write_phy_reg(pi, 0x452, command_num);
2796
2797                 if ((cal_type == 3) || (cal_type == 4)) {
2798                         wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2799                                                      &diq_start, 1, 16, 69);
2800
2801                         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2802                                                       &zero_diq, 1, 16, 69);
2803                 }
2804
2805                 write_phy_reg(pi, 0x451, cal_cmds[i]);
2806
2807                 if (!wlc_lcnphy_iqcal_wait(pi))
2808                         goto cleanup;
2809
2810                 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2811                                              best_coeffs,
2812                                              ARRAY_SIZE(best_coeffs), 16, 96);
2813                 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2814                                               best_coeffs,
2815                                               ARRAY_SIZE(best_coeffs), 16, 64);
2816
2817                 if ((cal_type == 3) || (cal_type == 4))
2818                         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2819                                                       &diq_start, 1, 16, 69);
2820                 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2821                                              pi_lcn->lcnphy_cal_results.
2822                                              txiqlocal_bestcoeffs,
2823                                              ARRAY_SIZE(pi_lcn->
2824                                                         lcnphy_cal_results.
2825                                                         txiqlocal_bestcoeffs),
2826                                              16, 96);
2827         }
2828
2829         wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2830                                      pi_lcn->lcnphy_cal_results.
2831                                      txiqlocal_bestcoeffs,
2832                                      ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
2833                                                 txiqlocal_bestcoeffs), 16, 96);
2834         pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
2835
2836         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2837                                       &pi_lcn->lcnphy_cal_results.
2838                                       txiqlocal_bestcoeffs[0], 4, 16, 80);
2839
2840         wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2841                                       &pi_lcn->lcnphy_cal_results.
2842                                       txiqlocal_bestcoeffs[5], 2, 16, 85);
2843
2844 cleanup:
2845         wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2846         kfree(values_to_save);
2847
2848         if (!keep_tone)
2849                 wlc_lcnphy_stop_tx_tone(pi);
2850
2851         write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2852
2853         write_phy_reg(pi, 0x453, 0);
2854
2855         if (tx_gain_override_old)
2856                 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2857         wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2858
2859         write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2860         write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2861
2862 }
2863
2864 static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
2865 {
2866         bool suspend, tx_gain_override_old;
2867         struct lcnphy_txgains old_gains;
2868         struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2869         u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2870             idleTssi0_regvalue_2C;
2871         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2872         u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2873         u16 SAVE_jtag_bb_afe_switch =
2874                 read_radio_reg(pi, RADIO_2064_REG007) & 1;
2875         u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2876         u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2877         u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi);
2878
2879         idleTssi = read_phy_reg(pi, 0x4ab);
2880         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2881                          MCTL_EN_MAC));
2882         if (!suspend)
2883                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2884         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2885
2886         tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2887         wlc_lcnphy_get_tx_gain(pi, &old_gains);
2888
2889         wlc_lcnphy_enable_tx_gain_override(pi);
2890         wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2891         write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2892         mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2893         mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2894         mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2895         wlc_lcnphy_tssi_setup(pi);
2896
2897         mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0));
2898         mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6));
2899
2900         wlc_lcnphy_set_bbmult(pi, 0x0);
2901
2902         wlc_phy_do_dummy_tx(pi, true, OFF);
2903         idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
2904                     >> 0);
2905
2906         idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2907                         >> 0);
2908
2909         if (idleTssi0_2C >= 256)
2910                 idleTssi0_OB = idleTssi0_2C - 256;
2911         else
2912                 idleTssi0_OB = idleTssi0_2C + 256;
2913
2914         idleTssi0_regvalue_OB = idleTssi0_OB;
2915         if (idleTssi0_regvalue_OB >= 256)
2916                 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2917         else
2918                 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2919         mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2920
2921         mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2922
2923         wlc_lcnphy_set_bbmult(pi, SAVE_bbmult);
2924         wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2925         wlc_lcnphy_set_tx_gain(pi, &old_gains);
2926         wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2927
2928         write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2929         mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2930         mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2931         mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2932         mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2933         if (!suspend)
2934                 wlapi_enable_mac(pi->sh->physhim);
2935 }
2936
2937 static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
2938 {
2939         bool suspend;
2940         u16 save_txpwrCtrlEn;
2941         u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2942         u16 auxpga_vmid;
2943         struct phytbl_info tab;
2944         u32 val;
2945         u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2946            save_reg112;
2947         u16 values_to_save[14];
2948         s8 index;
2949         int i;
2950         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2951         udelay(999);
2952
2953         save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
2954         save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
2955         save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
2956         save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
2957         save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
2958         save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
2959
2960         for (i = 0; i < 14; i++)
2961                 values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
2962         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2963                          MCTL_EN_MAC));
2964         if (!suspend)
2965                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2966         save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2967
2968         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2969         index = pi_lcn->lcnphy_current_index;
2970         wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2971         mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2972         mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2973         mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2974         mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2975
2976         mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2977
2978         mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2979
2980         mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2981
2982         mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2983
2984         mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2985
2986         mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2987
2988         mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2989
2990         mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2991
2992         mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2993
2994         mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2995
2996         mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2997
2998         mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2999
3000         mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
3001
3002         mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
3003
3004         mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
3005
3006         mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
3007
3008         mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
3009
3010         write_radio_reg(pi, RADIO_2064_REG025, 0xC);
3011
3012         mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
3013
3014         mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
3015
3016         mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
3017
3018         mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
3019
3020         val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
3021         tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
3022         tab.tbl_width = 16;
3023         tab.tbl_len = 1;
3024         tab.tbl_ptr = &val;
3025         tab.tbl_offset = 6;
3026         wlc_lcnphy_write_table(pi, &tab);
3027         if (mode == TEMPSENSE) {
3028                 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
3029
3030                 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
3031
3032                 auxpga_vmidcourse = 8;
3033                 auxpga_vmidfine = 0x4;
3034                 auxpga_gain = 2;
3035                 mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
3036         } else {
3037                 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
3038
3039                 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
3040
3041                 auxpga_vmidcourse = 7;
3042                 auxpga_vmidfine = 0xa;
3043                 auxpga_gain = 2;
3044         }
3045         auxpga_vmid =
3046                 (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
3047         mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
3048
3049         mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
3050
3051         mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
3052
3053         mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
3054
3055         mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
3056
3057         write_radio_reg(pi, RADIO_2064_REG112, 0x6);
3058
3059         wlc_phy_do_dummy_tx(pi, true, OFF);
3060         if (!tempsense_done(pi))
3061                 udelay(10);
3062
3063         write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
3064         write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
3065         write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
3066         write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
3067         write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
3068         write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
3069         for (i = 0; i < 14; i++)
3070                 write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
3071         wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
3072
3073         write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
3074         if (!suspend)
3075                 wlapi_enable_mac(pi->sh->physhim);
3076         udelay(999);
3077 }
3078
3079 static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
3080 {
3081         struct lcnphy_txgains tx_gains;
3082         u8 bbmult;
3083         struct phytbl_info tab;
3084         s32 a1, b0, b1;
3085         s32 tssi, pwr, maxtargetpwr, mintargetpwr;
3086         bool suspend;
3087         struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
3088
3089         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
3090                          MCTL_EN_MAC));
3091         if (!suspend)
3092                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3093
3094         if (!pi->hwpwrctrl_capable) {
3095                 if (CHSPEC_IS2G(pi->radio_chanspec)) {
3096                         tx_gains.gm_gain = 4;
3097                         tx_gains.pga_gain = 12;
3098                         tx_gains.pad_gain = 12;
3099                         tx_gains.dac_gain = 0;
3100
3101                         bbmult = 150;
3102                 } else {
3103                         tx_gains.gm_gain = 7;
3104                         tx_gains.pga_gain = 15;
3105                         tx_gains.pad_gain = 14;
3106                         tx_gains.dac_gain = 0;
3107
3108                         bbmult = 150;
3109                 }
3110                 wlc_lcnphy_set_tx_gain(pi, &tx_gains);
3111                 wlc_lcnphy_set_bbmult(pi, bbmult);
3112                 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3113         } else {
3114
3115                 wlc_lcnphy_idle_tssi_est(ppi);
3116
3117                 wlc_lcnphy_clear_tx_power_offsets(pi);
3118
3119                 b0 = pi->txpa_2g[0];
3120                 b1 = pi->txpa_2g[1];
3121                 a1 = pi->txpa_2g[2];
3122                 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
3123                 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3124
3125                 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3126                 tab.tbl_width = 32;
3127                 tab.tbl_ptr = &pwr;
3128                 tab.tbl_len = 1;
3129                 tab.tbl_offset = 0;
3130                 for (tssi = 0; tssi < 128; tssi++) {
3131                         pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3132
3133                         pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3134                         wlc_lcnphy_write_table(pi, &tab);
3135                         tab.tbl_offset++;
3136                 }
3137                 mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0);
3138                 mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0);
3139                 mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8);
3140                 mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4);
3141                 mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2);
3142
3143                 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
3144
3145                 write_phy_reg(pi, 0x4a8, 10);
3146
3147                 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
3148
3149                 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3150         }
3151         if (!suspend)
3152                 wlapi_enable_mac(pi->sh->physhim);
3153 }
3154
3155 static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain)
3156 {
3157         mod_phy_reg(pi, 0x4fb,
3158                     LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
3159                     gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
3160         mod_phy_reg(pi, 0x4fd,
3161                     LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
3162                     gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
3163 }
3164
3165 void
3166 wlc_lcnphy_get_radio_loft(struct brcms_phy *pi,
3167                           u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
3168 {
3169         *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
3170         *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
3171         *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
3172         *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
3173 }
3174
3175 void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b)
3176 {
3177         struct phytbl_info tab;
3178         u16 iqcc[2];
3179
3180         iqcc[0] = a;
3181         iqcc[1] = b;
3182
3183         tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3184         tab.tbl_width = 16;
3185         tab.tbl_ptr = iqcc;
3186         tab.tbl_len = 2;
3187         tab.tbl_offset = 80;
3188         wlc_lcnphy_write_table(pi, &tab);
3189 }
3190
3191 void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq)
3192 {
3193         struct phytbl_info tab;
3194
3195         tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3196         tab.tbl_width = 16;
3197         tab.tbl_ptr = &didq;
3198         tab.tbl_len = 1;
3199         tab.tbl_offset = 85;
3200         wlc_lcnphy_write_table(pi, &tab);
3201 }
3202
3203 void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index)
3204 {
3205         struct phytbl_info tab;
3206         u16 a, b;
3207         u8 bb_mult;
3208         u32 bbmultiqcomp, txgain, locoeffs, rfpower;
3209         struct lcnphy_txgains gains;
3210         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3211
3212         pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
3213         pi_lcn->lcnphy_current_index = (u8) index;
3214
3215         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3216         tab.tbl_width = 32;
3217         tab.tbl_len = 1;
3218
3219         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3220
3221         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
3222         tab.tbl_ptr = &bbmultiqcomp;
3223         wlc_lcnphy_read_table(pi, &tab);
3224
3225         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
3226         tab.tbl_width = 32;
3227         tab.tbl_ptr = &txgain;
3228         wlc_lcnphy_read_table(pi, &tab);
3229
3230         gains.gm_gain = (u16) (txgain & 0xff);
3231         gains.pga_gain = (u16) (txgain >> 8) & 0xff;
3232         gains.pad_gain = (u16) (txgain >> 16) & 0xff;
3233         gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
3234         wlc_lcnphy_set_tx_gain(pi, &gains);
3235         wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
3236
3237         bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
3238         wlc_lcnphy_set_bbmult(pi, bb_mult);
3239
3240         wlc_lcnphy_enable_tx_gain_override(pi);
3241
3242         if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3243
3244                 a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
3245                 b = (u16) (bbmultiqcomp & 0x3ff);
3246                 wlc_lcnphy_set_tx_iqcc(pi, a, b);
3247
3248                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
3249                 tab.tbl_ptr = &locoeffs;
3250                 wlc_lcnphy_read_table(pi, &tab);
3251
3252                 wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
3253
3254                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
3255                 tab.tbl_ptr = &rfpower;
3256                 wlc_lcnphy_read_table(pi, &tab);
3257                 mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
3258
3259         }
3260 }
3261
3262 static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)
3263 {
3264         u32 j;
3265         struct phytbl_info tab;
3266         u32 temp_offset[128];
3267         tab.tbl_ptr = temp_offset;
3268         tab.tbl_len = 128;
3269         tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
3270         tab.tbl_width = 32;
3271         tab.tbl_offset = 0;
3272
3273         memset(temp_offset, 0, sizeof(temp_offset));
3274         for (j = 1; j < 128; j += 2)
3275                 temp_offset[j] = 0x80000;
3276
3277         wlc_lcnphy_write_table(pi, &tab);
3278         return;
3279 }
3280
3281 void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)
3282 {
3283         if (!bEnable) {
3284
3285                 and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
3286
3287                 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
3288
3289                 and_phy_reg(pi, 0x44c,
3290                             ~(u16) ((0x1 << 3) |
3291                                     (0x1 << 5) |
3292                                     (0x1 << 12) |
3293                                     (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3294
3295                 and_phy_reg(pi, 0x44d,
3296                             ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
3297                 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
3298
3299                 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
3300
3301                 and_phy_reg(pi, 0x4f9,
3302                             ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3303
3304                 and_phy_reg(pi, 0x4fa,
3305                             ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3306         } else {
3307
3308                 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3309                 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3310
3311                 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
3312                 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
3313
3314                 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3315                 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3316
3317                 wlc_lcnphy_set_trsw_override(pi, true, false);
3318
3319                 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
3320                 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
3321
3322                 if (CHSPEC_IS2G(pi->radio_chanspec)) {
3323
3324                         mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3325                         mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
3326
3327                         mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3328                         mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
3329
3330                         mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3331                         mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
3332
3333                         mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3334                         mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
3335
3336                         mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3337                         mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
3338                 } else {
3339
3340                         mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3341                         mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
3342
3343                         mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3344                         mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
3345
3346                         mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3347                         mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
3348
3349                         mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3350                         mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
3351
3352                         mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3353                         mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3354                 }
3355         }
3356 }
3357
3358 static void
3359 wlc_lcnphy_run_samples(struct brcms_phy *pi,
3360                        u16 num_samps,
3361                        u16 num_loops, u16 wait, bool iqcalmode)
3362 {
3363
3364         or_phy_reg(pi, 0x6da, 0x8080);
3365
3366         mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
3367         if (num_loops != 0xffff)
3368                 num_loops--;
3369         mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
3370
3371         mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
3372
3373         if (iqcalmode) {
3374
3375                 and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
3376                 or_phy_reg(pi, 0x453, (0x1 << 15));
3377         } else {
3378                 write_phy_reg(pi, 0x63f, 1);
3379                 wlc_lcnphy_tx_pu(pi, 1);
3380         }
3381
3382         or_radio_reg(pi, RADIO_2064_REG112, 0x6);
3383 }
3384
3385 void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)
3386 {
3387
3388         u8 phybw40;
3389         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3390
3391         if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
3392                 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3393                 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3394         } else {
3395                 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3396                 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3397         }
3398
3399         if (phybw40 == 0) {
3400                 mod_phy_reg((pi), 0x410,
3401                             (0x1 << 6) |
3402                             (0x1 << 5),
3403                             ((CHSPEC_IS2G(
3404                                       pi->radio_chanspec)) ? (!mode) : 0) <<
3405                             6 | (!mode) << 5);
3406                 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
3407         }
3408 }
3409
3410 void
3411 wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
3412                          bool iqcalmode)
3413 {
3414         u8 phy_bw;
3415         u16 num_samps, t, k;
3416         u32 bw;
3417         s32 theta = 0, rot = 0;
3418         struct cordic_iq tone_samp;
3419         u32 data_buf[64];
3420         u16 i_samp, q_samp;
3421         struct phytbl_info tab;
3422         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3423
3424         pi->phy_tx_tone_freq = f_kHz;
3425
3426         wlc_lcnphy_deaf_mode(pi, true);
3427
3428         phy_bw = 40;
3429         if (pi_lcn->lcnphy_spurmod) {
3430                 write_phy_reg(pi, 0x942, 0x2);
3431                 write_phy_reg(pi, 0x93b, 0x0);
3432                 write_phy_reg(pi, 0x93c, 0x0);
3433                 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3434         }
3435
3436         if (f_kHz) {
3437                 k = 1;
3438                 do {
3439                         bw = phy_bw * 1000 * k;
3440                         num_samps = bw / abs(f_kHz);
3441                         k++;
3442                 } while ((num_samps * (u32) (abs(f_kHz))) != bw);
3443         } else
3444                 num_samps = 2;
3445
3446         rot = ((f_kHz * 36) / phy_bw) / 100;
3447         theta = 0;
3448
3449         for (t = 0; t < num_samps; t++) {
3450
3451                 tone_samp = cordic_calc_iq(theta);
3452
3453                 theta += rot;
3454
3455                 i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
3456                 q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
3457                 data_buf[t] = (i_samp << 10) | q_samp;
3458         }
3459
3460         mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
3461
3462         mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
3463
3464         tab.tbl_ptr = data_buf;
3465         tab.tbl_len = num_samps;
3466         tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
3467         tab.tbl_offset = 0;
3468         tab.tbl_width = 32;
3469         wlc_lcnphy_write_table(pi, &tab);
3470
3471         wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
3472 }
3473
3474 void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
3475 {
3476         s16 playback_status;
3477         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3478
3479         pi->phy_tx_tone_freq = 0;
3480         if (pi_lcn->lcnphy_spurmod) {
3481                 write_phy_reg(pi, 0x942, 0x7);
3482                 write_phy_reg(pi, 0x93b, 0x2017);
3483                 write_phy_reg(pi, 0x93c, 0x27c5);
3484                 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3485         }
3486
3487         playback_status = read_phy_reg(pi, 0x644);
3488         if (playback_status & (0x1 << 0)) {
3489                 wlc_lcnphy_tx_pu(pi, 0);
3490                 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
3491         } else if (playback_status & (0x1 << 1))
3492                 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
3493
3494         mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
3495
3496         mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
3497
3498         mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
3499
3500         and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
3501
3502         wlc_lcnphy_deaf_mode(pi, false);
3503 }
3504
3505 static void
3506 wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3507 {
3508         u16 di0dq0;
3509         u16 x, y, data_rf;
3510         int k;
3511         switch (cal_type) {
3512         case 0:
3513                 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3514                 break;
3515         case 2:
3516                 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3517                 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3518                 break;
3519         case 3:
3520                 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3521                 y = 8 + k;
3522                 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3523                 x = 8 - k;
3524                 data_rf = (x * 16 + y);
3525                 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3526                 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3527                 y = 8 + k;
3528                 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3529                 x = 8 - k;
3530                 data_rf = (x * 16 + y);
3531                 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3532                 break;
3533         case 4:
3534                 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3535                 y = 8 + k;
3536                 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3537                 x = 8 - k;
3538                 data_rf = (x * 16 + y);
3539                 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3540                 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3541                 y = 8 + k;
3542                 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3543                 x = 8 - k;
3544                 data_rf = (x * 16 + y);
3545                 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3546                 break;
3547         }
3548 }
3549
3550 static struct lcnphy_unsign16_struct
3551 wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
3552 {
3553         u16 a, b, didq;
3554         u8 di0, dq0, ei, eq, fi, fq;
3555         struct lcnphy_unsign16_struct cc;
3556         cc.re = 0;
3557         cc.im = 0;
3558         switch (cal_type) {
3559         case 0:
3560                 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3561                 cc.re = a;
3562                 cc.im = b;
3563                 break;
3564         case 2:
3565                 didq = wlc_lcnphy_get_tx_locc(pi);
3566                 di0 = (((didq & 0xff00) << 16) >> 24);
3567                 dq0 = (((didq & 0x00ff) << 24) >> 24);
3568                 cc.re = (u16) di0;
3569                 cc.im = (u16) dq0;
3570                 break;
3571         case 3:
3572                 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3573                 cc.re = (u16) ei;
3574                 cc.im = (u16) eq;
3575                 break;
3576         case 4:
3577                 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3578                 cc.re = (u16) fi;
3579                 cc.im = (u16) fq;
3580                 break;
3581         }
3582         return cc;
3583 }
3584
3585 static void
3586 wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
3587                     s16 *ptr, int mode)
3588 {
3589         u32 curval1, curval2, stpptr, curptr, strptr, val;
3590         u16 sslpnCalibClkEnCtrl, timer;
3591         u16 old_sslpnCalibClkEnCtrl;
3592         s16 imag, real;
3593         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3594
3595         timer = 0;
3596         old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3597
3598         curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));
3599         ptr[130] = 0;
3600         bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),
3601                      ((1 << 6) | curval1));
3602
3603         bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);
3604         bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);
3605         udelay(20);
3606         curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));
3607         bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),
3608                      curval2 | 0x30);
3609
3610         write_phy_reg(pi, 0x555, 0x0);
3611         write_phy_reg(pi, 0x5a6, 0x5);
3612
3613         write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3614         write_phy_reg(pi, 0x5cf, 3);
3615         write_phy_reg(pi, 0x5a5, 0x3);
3616         write_phy_reg(pi, 0x583, 0x0);
3617         write_phy_reg(pi, 0x584, 0x0);
3618         write_phy_reg(pi, 0x585, 0x0fff);
3619         write_phy_reg(pi, 0x586, 0x0000);
3620
3621         write_phy_reg(pi, 0x580, 0x4501);
3622
3623         sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3624         write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3625         stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));
3626         curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3627         do {
3628                 udelay(10);
3629                 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3630                 timer++;
3631         } while ((curptr != stpptr) && (timer < 500));
3632
3633         bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);
3634         strptr = 0x7E00;
3635         bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);
3636         while (strptr < 0x8000) {
3637                 val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));
3638                 imag = ((val >> 16) & 0x3ff);
3639                 real = ((val) & 0x3ff);
3640                 if (imag > 511)
3641                         imag -= 1024;
3642
3643                 if (real > 511)
3644                         real -= 1024;
3645
3646                 if (pi_lcn->lcnphy_iqcal_swp_dis)
3647                         ptr[(strptr - 0x7E00) / 4] = real;
3648                 else
3649                         ptr[(strptr - 0x7E00) / 4] = imag;
3650
3651                 if (clip_detect_algo) {
3652                         if (imag > thresh || imag < -thresh) {
3653                                 strptr = 0x8000;
3654                                 ptr[130] = 1;
3655                         }
3656                 }
3657
3658                 strptr += 4;
3659         }
3660
3661         write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3662         bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);
3663         bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);
3664 }
3665
3666 static void
3667 wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
3668               int step_size_lg2)
3669 {
3670         const struct lcnphy_spb_tone *phy_c1;
3671         struct lcnphy_spb_tone phy_c2;
3672         struct lcnphy_unsign16_struct phy_c3;
3673         int phy_c4, phy_c5, k, l, j, phy_c6;
3674         u16 phy_c7, phy_c8, phy_c9;
3675         s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
3676         s16 *ptr, phy_c17;
3677         s32 phy_c18, phy_c19;
3678         u32 phy_c20, phy_c21;
3679         bool phy_c22, phy_c23, phy_c24, phy_c25;
3680         u16 phy_c26, phy_c27;
3681         u16 phy_c28, phy_c29, phy_c30;
3682         u16 phy_c31;
3683         u16 *phy_c32;
3684         phy_c21 = 0;
3685         phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
3686         ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
3687         if (NULL == ptr)
3688                 return;
3689
3690         phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
3691         if (NULL == phy_c32) {
3692                 kfree(ptr);
3693                 return;
3694         }
3695         phy_c26 = read_phy_reg(pi, 0x6da);
3696         phy_c27 = read_phy_reg(pi, 0x6db);
3697         phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
3698         write_phy_reg(pi, 0x93d, 0xC0);
3699
3700         wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
3701         write_phy_reg(pi, 0x6da, 0xffff);
3702         or_phy_reg(pi, 0x6db, 0x3);
3703
3704         wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
3705         udelay(500);
3706         phy_c28 = read_phy_reg(pi, 0x938);
3707         phy_c29 = read_phy_reg(pi, 0x4d7);
3708         phy_c30 = read_phy_reg(pi, 0x4d8);
3709         or_phy_reg(pi, 0x938, 0x1 << 2);
3710         or_phy_reg(pi, 0x4d7, 0x1 << 2);
3711         or_phy_reg(pi, 0x4d7, 0x1 << 3);
3712         mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
3713         or_phy_reg(pi, 0x4d8, 1 << 0);
3714         or_phy_reg(pi, 0x4d8, 1 << 1);
3715         mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
3716         mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
3717         phy_c1 = &lcnphy_spb_tone_3750[0];
3718         phy_c4 = 32;
3719
3720         if (num_levels == 0) {
3721                 if (cal_type != 0)
3722                         num_levels = 4;
3723                 else
3724                         num_levels = 9;
3725         }
3726         if (step_size_lg2 == 0) {
3727                 if (cal_type != 0)
3728                         step_size_lg2 = 3;
3729                 else
3730                         step_size_lg2 = 8;
3731         }
3732
3733         phy_c7 = (1 << step_size_lg2);
3734         phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
3735         phy_c15 = (s16) phy_c3.re;
3736         phy_c16 = (s16) phy_c3.im;
3737         if (cal_type == 2) {
3738                 if (phy_c3.re > 127)
3739                         phy_c15 = phy_c3.re - 256;
3740                 if (phy_c3.im > 127)
3741                         phy_c16 = phy_c3.im - 256;
3742         }
3743         wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3744         udelay(20);
3745         for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
3746                 phy_c23 = true;
3747                 phy_c22 = false;
3748                 switch (cal_type) {
3749                 case 0:
3750                         phy_c10 = 511;
3751                         break;
3752                 case 2:
3753                         phy_c10 = 127;
3754                         break;
3755                 case 3:
3756                         phy_c10 = 15;
3757                         break;
3758                 case 4:
3759                         phy_c10 = 15;
3760                         break;
3761                 }
3762
3763                 phy_c9 = read_phy_reg(pi, 0x93d);
3764                 phy_c9 = 2 * phy_c9;
3765                 phy_c24 = false;
3766                 phy_c5 = 7;
3767                 phy_c25 = true;
3768                 while (1) {
3769                         write_radio_reg(pi, RADIO_2064_REG026,
3770                                         (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
3771                         udelay(50);
3772                         phy_c22 = false;
3773                         ptr[130] = 0;
3774                         wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
3775                         if (ptr[130] == 1)
3776                                 phy_c22 = true;
3777                         if (phy_c22)
3778                                 phy_c5 -= 1;
3779                         if ((phy_c22 != phy_c24) && (!phy_c25))
3780                                 break;
3781                         if (!phy_c22)
3782                                 phy_c5 += 1;
3783                         if (phy_c5 <= 0 || phy_c5 >= 7)
3784                                 break;
3785                         phy_c24 = phy_c22;
3786                         phy_c25 = false;
3787                 }
3788
3789                 if (phy_c5 < 0)
3790                         phy_c5 = 0;
3791                 else if (phy_c5 > 7)
3792                         phy_c5 = 7;
3793
3794                 for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
3795                         for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
3796                                 phy_c11 = phy_c15 + k;
3797                                 phy_c12 = phy_c16 + l;
3798
3799                                 if (phy_c11 < -phy_c10)
3800                                         phy_c11 = -phy_c10;
3801                                 else if (phy_c11 > phy_c10)
3802                                         phy_c11 = phy_c10;
3803                                 if (phy_c12 < -phy_c10)
3804                                         phy_c12 = -phy_c10;
3805                                 else if (phy_c12 > phy_c10)
3806                                         phy_c12 = phy_c10;
3807                                 wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
3808                                                   phy_c12);
3809                                 udelay(20);
3810                                 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
3811
3812                                 phy_c18 = 0;
3813                                 phy_c19 = 0;
3814                                 for (j = 0; j < 128; j++) {
3815                                         if (cal_type != 0)
3816                                                 phy_c6 = j % phy_c4;
3817                                         else
3818                                                 phy_c6 = (2 * j) % phy_c4;
3819
3820                                         phy_c2.re = phy_c1[phy_c6].re;
3821                                         phy_c2.im = phy_c1[phy_c6].im;
3822                                         phy_c17 = ptr[j];
3823                                         phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
3824                                         phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
3825                                 }
3826
3827                                 phy_c18 = phy_c18 >> 10;
3828                                 phy_c19 = phy_c19 >> 10;
3829                                 phy_c20 = ((phy_c18 * phy_c18) +
3830                                            (phy_c19 * phy_c19));
3831
3832                                 if (phy_c23 || phy_c20 < phy_c21) {
3833                                         phy_c21 = phy_c20;
3834                                         phy_c13 = phy_c11;
3835                                         phy_c14 = phy_c12;
3836                                 }
3837                                 phy_c23 = false;
3838                         }
3839                 }
3840                 phy_c23 = true;
3841                 phy_c15 = phy_c13;
3842                 phy_c16 = phy_c14;
3843                 phy_c7 = phy_c7 >> 1;
3844                 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3845                 udelay(20);
3846         }
3847         goto cleanup;
3848 cleanup:
3849         wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
3850         wlc_lcnphy_stop_tx_tone(pi);
3851         write_phy_reg(pi, 0x6da, phy_c26);
3852         write_phy_reg(pi, 0x6db, phy_c27);
3853         write_phy_reg(pi, 0x938, phy_c28);
3854         write_phy_reg(pi, 0x4d7, phy_c29);
3855         write_phy_reg(pi, 0x4d8, phy_c30);
3856         write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
3857
3858         kfree(phy_c32);
3859         kfree(ptr);
3860 }
3861
3862 void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
3863 {
3864         u16 iqcc[2];
3865         struct phytbl_info tab;
3866
3867         tab.tbl_ptr = iqcc;
3868         tab.tbl_len = 2;
3869         tab.tbl_id = 0;
3870         tab.tbl_offset = 80;
3871         tab.tbl_width = 16;
3872         wlc_lcnphy_read_table(pi, &tab);
3873
3874         *a = iqcc[0];
3875         *b = iqcc[1];
3876 }
3877
3878 static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
3879 {
3880         struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3881
3882         wlc_lcnphy_set_cc(pi, 0, 0, 0);
3883         wlc_lcnphy_set_cc(pi, 2, 0, 0);
3884         wlc_lcnphy_set_cc(pi, 3, 0, 0);
3885         wlc_lcnphy_set_cc(pi, 4, 0, 0);
3886
3887         wlc_lcnphy_a1(pi, 4, 0, 0);
3888         wlc_lcnphy_a1(pi, 3, 0, 0);
3889         wlc_lcnphy_a1(pi, 2, 3, 2);
3890         wlc_lcnphy_a1(pi, 0, 5, 8);
3891         wlc_lcnphy_a1(pi, 2, 2, 1);
3892         wlc_lcnphy_a1(pi, 0, 4, 3);
3893
3894         iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3895         locc2 = wlc_lcnphy_get_cc(pi, 2);
3896         locc3 = wlc_lcnphy_get_cc(pi, 3);
3897         locc4 = wlc_lcnphy_get_cc(pi, 4);
3898 }
3899
3900 u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
3901 {
3902         struct phytbl_info tab;
3903         u16 didq;
3904
3905         tab.tbl_id = 0;
3906         tab.tbl_width = 16;
3907         tab.tbl_ptr = &didq;
3908         tab.tbl_len = 1;
3909         tab.tbl_offset = 85;
3910         wlc_lcnphy_read_table(pi, &tab);
3911
3912         return didq;
3913 }
3914
3915 static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
3916 {
3917
3918         struct lcnphy_txgains target_gains, old_gains;
3919         u8 save_bb_mult;
3920         u16 a, b, didq, save_pa_gain = 0;
3921         uint idx, SAVE_txpwrindex = 0xFF;
3922         u32 val;
3923         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3924         struct phytbl_info tab;
3925         u8 ei0, eq0, fi0, fq0;
3926         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3927
3928         wlc_lcnphy_get_tx_gain(pi, &old_gains);
3929         save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
3930
3931         save_bb_mult = wlc_lcnphy_get_bbmult(pi);
3932
3933         if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
3934                 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
3935
3936         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3937
3938         target_gains.gm_gain = 7;
3939         target_gains.pga_gain = 0;
3940         target_gains.pad_gain = 21;
3941         target_gains.dac_gain = 0;
3942         wlc_lcnphy_set_tx_gain(pi, &target_gains);
3943
3944         if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
3945
3946                 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
3947
3948                 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3949                                        (pi_lcn->
3950                                         lcnphy_recal ? LCNPHY_CAL_RECAL :
3951                                         LCNPHY_CAL_FULL), false);
3952         } else {
3953                 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3954                 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3955         }
3956
3957         wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
3958         if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
3959                 if (CHSPEC_IS5G(pi->radio_chanspec)) {
3960                         target_gains.gm_gain = 255;
3961                         target_gains.pga_gain = 255;
3962                         target_gains.pad_gain = 0xf0;
3963                         target_gains.dac_gain = 0;
3964                 } else {
3965                         target_gains.gm_gain = 7;
3966                         target_gains.pga_gain = 45;
3967                         target_gains.pad_gain = 186;
3968                         target_gains.dac_gain = 0;
3969                 }
3970
3971                 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
3972                     || pi_lcn->lcnphy_hw_iqcal_en) {
3973
3974                         target_gains.pga_gain = 0;
3975                         target_gains.pad_gain = 30;
3976                         wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3977                         wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3978                                                LCNPHY_CAL_FULL, false);
3979                 } else {
3980                         wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3981                 }
3982         }
3983
3984         wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3985
3986         didq = wlc_lcnphy_get_tx_locc(pi);
3987
3988         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3989         tab.tbl_width = 32;
3990         tab.tbl_ptr = &val;
3991
3992         tab.tbl_len = 1;
3993         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
3994
3995         for (idx = 0; idx < 128; idx++) {
3996                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
3997
3998                 wlc_lcnphy_read_table(pi, &tab);
3999                 val = (val & 0xfff00000) |
4000                       ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
4001                 wlc_lcnphy_write_table(pi, &tab);
4002
4003                 val = didq;
4004                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
4005                 wlc_lcnphy_write_table(pi, &tab);
4006         }
4007
4008         pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
4009         pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
4010         pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
4011         pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
4012         pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
4013         pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
4014         pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
4015
4016         wlc_lcnphy_set_bbmult(pi, save_bb_mult);
4017         wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
4018         wlc_lcnphy_set_tx_gain(pi, &old_gains);
4019
4020         if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
4021                 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4022         else
4023                 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
4024 }
4025
4026 s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
4027 {
4028         u16 tempsenseval1, tempsenseval2;
4029         s16 avg = 0;
4030         bool suspend = false;
4031
4032         if (mode == 1) {
4033                 suspend = (0 == (bcma_read32(pi->d11core,
4034                                              D11REGOFFS(maccontrol)) &
4035                                  MCTL_EN_MAC));
4036                 if (!suspend)
4037                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
4038                 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4039         }
4040         tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4041         tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4042
4043         if (tempsenseval1 > 255)
4044                 avg = (s16) (tempsenseval1 - 512);
4045         else
4046                 avg = (s16) tempsenseval1;
4047
4048         if (tempsenseval2 > 255)
4049                 avg += (s16) (tempsenseval2 - 512);
4050         else
4051                 avg += (s16) tempsenseval2;
4052
4053         avg /= 2;
4054
4055         if (mode == 1) {
4056
4057                 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4058
4059                 udelay(100);
4060                 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4061
4062                 if (!suspend)
4063                         wlapi_enable_mac(pi->sh->physhim);
4064         }
4065         return avg;
4066 }
4067
4068 u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
4069 {
4070         u16 tempsenseval1, tempsenseval2;
4071         s32 avg = 0;
4072         bool suspend = false;
4073         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4074         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4075
4076         if (mode == 1) {
4077                 suspend = (0 == (bcma_read32(pi->d11core,
4078                                              D11REGOFFS(maccontrol)) &
4079                                  MCTL_EN_MAC));
4080                 if (!suspend)
4081                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
4082                 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4083         }
4084         tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4085         tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4086
4087         if (tempsenseval1 > 255)
4088                 avg = (int)(tempsenseval1 - 512);
4089         else
4090                 avg = (int)tempsenseval1;
4091
4092         if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
4093                 if (tempsenseval2 > 255)
4094                         avg = (int)(avg - tempsenseval2 + 512);
4095                 else
4096                         avg = (int)(avg - tempsenseval2);
4097         } else {
4098                 if (tempsenseval2 > 255)
4099                         avg = (int)(avg + tempsenseval2 - 512);
4100                 else
4101                         avg = (int)(avg + tempsenseval2);
4102                 avg = avg / 2;
4103         }
4104         if (avg < 0)
4105                 avg = avg + 512;
4106
4107         if (pi_lcn->lcnphy_tempsense_option == 2)
4108                 avg = tempsenseval1;
4109
4110         if (mode)
4111                 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4112
4113         if (mode == 1) {
4114
4115                 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4116
4117                 udelay(100);
4118                 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4119
4120                 if (!suspend)
4121                         wlapi_enable_mac(pi->sh->physhim);
4122         }
4123         return (u16) avg;
4124 }
4125
4126 s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
4127 {
4128         s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
4129         degree =
4130                 ((degree <<
4131                   10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
4132                 / LCN_TEMPSENSE_DEN;
4133         return (s8) degree;
4134 }
4135
4136 s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
4137 {
4138         u16 vbatsenseval;
4139         s32 avg = 0;
4140         bool suspend = false;
4141
4142         if (mode == 1) {
4143                 suspend = (0 == (bcma_read32(pi->d11core,
4144                                              D11REGOFFS(maccontrol)) &
4145                                  MCTL_EN_MAC));
4146                 if (!suspend)
4147                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
4148                 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
4149         }
4150
4151         vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
4152
4153         if (vbatsenseval > 255)
4154                 avg = (s32) (vbatsenseval - 512);
4155         else
4156                 avg = (s32) vbatsenseval;
4157
4158         avg =   (avg * LCN_VBAT_SCALE_NOM +
4159                  (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
4160
4161         if (mode == 1) {
4162                 if (!suspend)
4163                         wlapi_enable_mac(pi->sh->physhim);
4164         }
4165         return (s8) avg;
4166 }
4167
4168 static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
4169 {
4170         u8 phybw40;
4171         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4172
4173         mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
4174
4175         if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
4176             (mode == AFE_CLK_INIT_MODE_TXRX2X))
4177                 write_phy_reg(pi, 0x6d0, 0x7);
4178
4179         wlc_lcnphy_toggle_afe_pwdn(pi);
4180 }
4181
4182 static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4183 {
4184 }
4185
4186 static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
4187 {
4188         bool suspend;
4189         s8 index;
4190         u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4191         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4192         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4193                          MCTL_EN_MAC));
4194         if (!suspend)
4195                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4196         wlc_lcnphy_deaf_mode(pi, true);
4197         pi->phy_lastcal = pi->sh->now;
4198         pi->phy_forcecal = false;
4199         index = pi_lcn->lcnphy_current_index;
4200
4201         wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4202
4203         wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4204         wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4205         wlc_lcnphy_deaf_mode(pi, false);
4206         if (!suspend)
4207                 wlapi_enable_mac(pi->sh->physhim);
4208
4209 }
4210
4211 static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
4212 {
4213         bool suspend, full_cal;
4214         const struct lcnphy_rx_iqcomp *rx_iqcomp;
4215         int rx_iqcomp_sz;
4216         u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4217         s8 index;
4218         struct phytbl_info tab;
4219         s32 a1, b0, b1;
4220         s32 tssi, pwr, maxtargetpwr, mintargetpwr;
4221         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4222
4223         pi->phy_lastcal = pi->sh->now;
4224         pi->phy_forcecal = false;
4225         full_cal =
4226                 (pi_lcn->lcnphy_full_cal_channel !=
4227                  CHSPEC_CHANNEL(pi->radio_chanspec));
4228         pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
4229         index = pi_lcn->lcnphy_current_index;
4230
4231         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4232                          MCTL_EN_MAC));
4233         if (!suspend) {
4234                 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
4235                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4236         }
4237
4238         wlc_lcnphy_deaf_mode(pi, true);
4239
4240         wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4241
4242         rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
4243         rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
4244
4245         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4246                 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
4247         else
4248                 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
4249
4250         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4251
4252                 wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
4253
4254                 b0 = pi->txpa_2g[0];
4255                 b1 = pi->txpa_2g[1];
4256                 a1 = pi->txpa_2g[2];
4257                 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
4258                 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
4259
4260                 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4261                 tab.tbl_width = 32;
4262                 tab.tbl_ptr = &pwr;
4263                 tab.tbl_len = 1;
4264                 tab.tbl_offset = 0;
4265                 for (tssi = 0; tssi < 128; tssi++) {
4266                         pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
4267                         pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
4268                         wlc_lcnphy_write_table(pi, &tab);
4269                         tab.tbl_offset++;
4270                 }
4271         }
4272
4273         wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4274         wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4275         wlc_lcnphy_deaf_mode(pi, false);
4276         if (!suspend)
4277                 wlapi_enable_mac(pi->sh->physhim);
4278 }
4279
4280 void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
4281 {
4282         u16 temp_new;
4283         int temp1, temp2, temp_diff;
4284         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4285
4286         switch (mode) {
4287         case PHY_PERICAL_CHAN:
4288                 break;
4289         case PHY_FULLCAL:
4290                 wlc_lcnphy_periodic_cal(pi);
4291                 break;
4292         case PHY_PERICAL_PHYINIT:
4293                 wlc_lcnphy_periodic_cal(pi);
4294                 break;
4295         case PHY_PERICAL_WATCHDOG:
4296                 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4297                         temp_new = wlc_lcnphy_tempsense(pi, 0);
4298                         temp1 = LCNPHY_TEMPSENSE(temp_new);
4299                         temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
4300                         temp_diff = temp1 - temp2;
4301                         if ((pi_lcn->lcnphy_cal_counter > 90) ||
4302                             (temp_diff > 60) || (temp_diff < -60)) {
4303                                 wlc_lcnphy_glacial_timer_based_cal(pi);
4304                                 wlc_2064_vco_cal(pi);
4305                                 pi_lcn->lcnphy_cal_temper = temp_new;
4306                                 pi_lcn->lcnphy_cal_counter = 0;
4307                         } else
4308                                 pi_lcn->lcnphy_cal_counter++;
4309                 }
4310                 break;
4311         case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
4312                 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4313                         wlc_lcnphy_tx_power_adjustment(
4314                                 (struct brcms_phy_pub *) pi);
4315                 break;
4316         }
4317 }
4318
4319 void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
4320 {
4321         s8 cck_offset;
4322         u16 status;
4323         status = (read_phy_reg(pi, 0x4ab));
4324         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
4325             (status  & (0x1 << 15))) {
4326                 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
4327                                    >> 0) >> 1);
4328
4329                 if (wlc_phy_tpc_isenabled_lcnphy(pi))
4330                         cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
4331                 else
4332                         cck_offset = 0;
4333
4334                 *cck_pwr = *ofdm_pwr + cck_offset;
4335         } else {
4336                 *cck_pwr = 0;
4337                 *ofdm_pwr = 0;
4338         }
4339 }
4340
4341 void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4342 {
4343         return;
4344
4345 }
4346
4347 void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
4348 {
4349         s8 index;
4350         u16 index2;
4351         struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
4352         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4353         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4354         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
4355             SAVE_txpwrctrl) {
4356                 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
4357                 index2 = (u16) (index * 2);
4358                 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
4359
4360                 pi_lcn->lcnphy_current_index =
4361                         (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
4362         }
4363 }
4364
4365 static void
4366 wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
4367                               const struct lcnphy_tx_gain_tbl_entry *gain_table)
4368 {
4369         u32 j;
4370         struct phytbl_info tab;
4371         u32 val;
4372         u16 pa_gain;
4373         u16 gm_gain;
4374
4375         if (pi->sh->boardflags & BFL_FEM)
4376                 pa_gain = 0x10;
4377         else
4378                 pa_gain = 0x60;
4379         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4380         tab.tbl_width = 32;
4381         tab.tbl_len = 1;
4382         tab.tbl_ptr = &val;
4383
4384         /* fixed gm_gain value for iPA */
4385         gm_gain = 15;
4386         for (j = 0; j < 128; j++) {
4387                 if (pi->sh->boardflags & BFL_FEM)
4388                         gm_gain = gain_table[j].gm;
4389                 val = (((u32) pa_gain << 24) |
4390                        (gain_table[j].pad << 16) |
4391                        (gain_table[j].pga << 8) | gm_gain);
4392
4393                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4394                 wlc_lcnphy_write_table(pi, &tab);
4395
4396                 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4397                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4398                 wlc_lcnphy_write_table(pi, &tab);
4399         }
4400 }
4401
4402 static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
4403 {
4404         struct phytbl_info tab;
4405         u32 val, bbmult, rfgain;
4406         u8 index;
4407         u8 scale_factor = 1;
4408         s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4409
4410         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4411         tab.tbl_width = 32;
4412         tab.tbl_len = 1;
4413
4414         for (index = 0; index < 128; index++) {
4415                 tab.tbl_ptr = &bbmult;
4416                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4417                 wlc_lcnphy_read_table(pi, &tab);
4418                 bbmult = bbmult >> 20;
4419
4420                 tab.tbl_ptr = &rfgain;
4421                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4422                 wlc_lcnphy_read_table(pi, &tab);
4423
4424                 qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4425                 qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4426
4427                 if (qQ1 < qQ2) {
4428                         temp2 = qm_shr16(temp2, qQ2 - qQ1);
4429                         qQ = qQ1;
4430                 } else {
4431                         temp1 = qm_shr16(temp1, qQ1 - qQ2);
4432                         qQ = qQ2;
4433                 }
4434                 temp = qm_sub16(temp1, temp2);
4435
4436                 if (qQ >= 4)
4437                         shift = qQ - 4;
4438                 else
4439                         shift = 4 - qQ;
4440
4441                 val = (((index << shift) + (5 * temp) +
4442                         (1 << (scale_factor + shift - 3))) >> (scale_factor +
4443                                                                shift - 2));
4444
4445                 tab.tbl_ptr = &val;
4446                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4447                 wlc_lcnphy_write_table(pi, &tab);
4448         }
4449 }
4450
4451 static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
4452 {
4453         or_phy_reg(pi, 0x805, 0x1);
4454
4455         mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4456
4457         mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4458
4459         write_phy_reg(pi, 0x414, 0x1e10);
4460         write_phy_reg(pi, 0x415, 0x0640);
4461
4462         mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4463
4464         or_phy_reg(pi, 0x44a, 0x44);
4465         write_phy_reg(pi, 0x44a, 0x80);
4466         mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4467
4468         mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4469
4470         if (!(pi->sh->boardrev < 0x1204))
4471                 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4472
4473         write_phy_reg(pi, 0x7d6, 0x0902);
4474         mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4475
4476         mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4477
4478         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4479                 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4480
4481                 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4482
4483                 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4484
4485                 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4486
4487                 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4488
4489                 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4490                 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4491                 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4492                 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4493                 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4494
4495                 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4496
4497                 wlc_lcnphy_clear_tx_power_offsets(pi);
4498                 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4499
4500         }
4501 }
4502
4503 static void wlc_lcnphy_rcal(struct brcms_phy *pi)
4504 {
4505         u8 rcal_value;
4506
4507         and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4508
4509         or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4510         or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4511
4512         or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4513         or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4514
4515         or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4516
4517         or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4518         mdelay(5);
4519         SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4520
4521         if (wlc_radio_2064_rcal_done(pi)) {
4522                 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4523                 rcal_value = rcal_value & 0x1f;
4524         }
4525
4526         and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4527
4528         and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4529 }
4530
4531 static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
4532 {
4533         u8 dflt_rc_cal_val;
4534         u16 flt_val;
4535
4536         dflt_rc_cal_val = 7;
4537         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4538                 dflt_rc_cal_val = 11;
4539         flt_val =
4540                 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4541                 (dflt_rc_cal_val);
4542         write_phy_reg(pi, 0x933, flt_val);
4543         write_phy_reg(pi, 0x934, flt_val);
4544         write_phy_reg(pi, 0x935, flt_val);
4545         write_phy_reg(pi, 0x936, flt_val);
4546         write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4547
4548         return;
4549 }
4550
4551 static void wlc_radio_2064_init(struct brcms_phy *pi)
4552 {
4553         u32 i;
4554         const struct lcnphy_radio_regs *lcnphyregs = NULL;
4555
4556         lcnphyregs = lcnphy_radio_regs_2064;
4557
4558         for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4559                 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4560                         write_radio_reg(pi,
4561                                         ((lcnphyregs[i].address & 0x3fff) |
4562                                          RADIO_DEFAULT_CORE),
4563                                         (u16) lcnphyregs[i].init_a);
4564                 else if (lcnphyregs[i].do_init_g)
4565                         write_radio_reg(pi,
4566                                         ((lcnphyregs[i].address & 0x3fff) |
4567                                          RADIO_DEFAULT_CORE),
4568                                         (u16) lcnphyregs[i].init_g);
4569
4570         write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4571         write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4572
4573         write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4574
4575         write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4576
4577         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4578
4579                 write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4580                 write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4581                 write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4582         }
4583
4584         write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4585         write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4586
4587         mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4588
4589         mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4590
4591         mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4592
4593         mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4594
4595         mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4596
4597         write_phy_reg(pi, 0x4ea, 0x4688);
4598
4599         if (pi->sh->boardflags & BFL_FEM)
4600                 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4601         else
4602                 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);
4603
4604         mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4605
4606         mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4607
4608         wlc_lcnphy_set_tx_locc(pi, 0);
4609
4610         wlc_lcnphy_rcal(pi);
4611
4612         wlc_lcnphy_rc_cal(pi);
4613
4614         if (!(pi->sh->boardflags & BFL_FEM)) {
4615                 write_radio_reg(pi, RADIO_2064_REG032, 0x6f);
4616                 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4617                 write_radio_reg(pi, RADIO_2064_REG039, 0xe);
4618         }
4619
4620 }
4621
4622 static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4623 {
4624         wlc_radio_2064_init(pi);
4625 }
4626
4627 static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
4628 {
4629         uint idx;
4630         u8 phybw40;
4631         struct phytbl_info tab;
4632         const struct phytbl_info *tb;
4633         u32 val;
4634
4635         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4636
4637         for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
4638                 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4639
4640         if (pi->sh->boardflags & BFL_FEM_BT) {
4641                 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4642                 tab.tbl_width = 16;
4643                 tab.tbl_ptr = &val;
4644                 tab.tbl_len = 1;
4645                 val = 100;
4646                 tab.tbl_offset = 4;
4647                 wlc_lcnphy_write_table(pi, &tab);
4648         }
4649
4650         if (!(pi->sh->boardflags & BFL_FEM)) {
4651                 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4652                 tab.tbl_width = 16;
4653                 tab.tbl_ptr = &val;
4654                 tab.tbl_len = 1;
4655
4656                 val = 150;
4657                 tab.tbl_offset = 0;
4658                 wlc_lcnphy_write_table(pi, &tab);
4659
4660                 val = 220;
4661                 tab.tbl_offset = 1;
4662                 wlc_lcnphy_write_table(pi, &tab);
4663         }
4664
4665         if (CHSPEC_IS2G(pi->radio_chanspec)) {
4666                 if (pi->sh->boardflags & BFL_FEM)
4667                         wlc_lcnphy_load_tx_gain_table(
4668                                 pi,
4669                                 dot11lcnphy_2GHz_extPA_gaintable_rev0);
4670                 else
4671                         wlc_lcnphy_load_tx_gain_table(
4672                                 pi,
4673                                 dot11lcnphy_2GHz_gaintable_rev0);
4674         }
4675
4676         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4677                 int l;
4678
4679                 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4680                         l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4681                         if (pi->sh->boardflags & BFL_EXTLNA)
4682                                 tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
4683                         else
4684                                 tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
4685                 } else {
4686                         l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4687                         if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4688                                 tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
4689                         else
4690                                 tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
4691                 }
4692
4693                 for (idx = 0; idx < l; idx++)
4694                         wlc_lcnphy_write_table(pi, &tb[idx]);
4695         }
4696
4697         if (pi->sh->boardflags & BFL_FEM) {
4698                 if (pi->sh->boardflags & BFL_FEM_BT) {
4699                         if (pi->sh->boardrev < 0x1250)
4700                                 tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
4701                         else
4702                                 tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
4703                 } else {
4704                         tb = &dot11lcn_sw_ctrl_tbl_info_4313_epa;
4705                 }
4706         } else {
4707                 if (pi->sh->boardflags & BFL_FEM_BT)
4708                         tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa;
4709                 else
4710                         tb = &dot11lcn_sw_ctrl_tbl_info_4313;
4711         }
4712         wlc_lcnphy_write_table(pi, tb);
4713         wlc_lcnphy_load_rfpower(pi);
4714
4715         wlc_lcnphy_clear_papd_comptable(pi);
4716 }
4717
4718 static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
4719 {
4720         u16 afectrl1;
4721         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4722
4723         write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4724
4725         write_phy_reg(pi, 0x43b, 0x0);
4726         write_phy_reg(pi, 0x43c, 0x0);
4727         write_phy_reg(pi, 0x44c, 0x0);
4728         write_phy_reg(pi, 0x4e6, 0x0);
4729         write_phy_reg(pi, 0x4f9, 0x0);
4730         write_phy_reg(pi, 0x4b0, 0x0);
4731         write_phy_reg(pi, 0x938, 0x0);
4732         write_phy_reg(pi, 0x4b0, 0x0);
4733         write_phy_reg(pi, 0x44e, 0);
4734
4735         or_phy_reg(pi, 0x567, 0x03);
4736
4737         or_phy_reg(pi, 0x44a, 0x44);
4738         write_phy_reg(pi, 0x44a, 0x80);
4739
4740         if (!(pi->sh->boardflags & BFL_FEM))
4741                 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4742
4743         if (0) {
4744                 afectrl1 = 0;
4745                 afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4746                                   (pi_lcn->lcnphy_rssi_vc << 4) |
4747                                   (pi_lcn->lcnphy_rssi_gs << 10));
4748                 write_phy_reg(pi, 0x43e, afectrl1);
4749         }
4750
4751         mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4752         if (pi->sh->boardflags & BFL_FEM) {
4753                 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4754
4755                 write_phy_reg(pi, 0x910, 0x1);
4756         }
4757
4758         mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4759         mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4760         mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4761
4762 }
4763
4764 static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
4765 {
4766         if (CHSPEC_IS5G(pi->radio_chanspec)) {
4767                 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4768                 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4769         }
4770 }
4771
4772 static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
4773 {
4774         s16 temp;
4775         struct phytbl_info tab;
4776         u32 tableBuffer[2];
4777         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4778
4779         temp = (s16) read_phy_reg(pi, 0x4df);
4780         pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4781
4782         if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4783                 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4784
4785         pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4786
4787         if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4788                 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4789
4790         tab.tbl_ptr = tableBuffer;
4791         tab.tbl_len = 2;
4792         tab.tbl_id = 17;
4793         tab.tbl_offset = 59;
4794         tab.tbl_width = 32;
4795         wlc_lcnphy_read_table(pi, &tab);
4796
4797         if (tableBuffer[0] > 63)
4798                 tableBuffer[0] -= 128;
4799         pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4800
4801         if (tableBuffer[1] > 63)
4802                 tableBuffer[1] -= 128;
4803         pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4804
4805         temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
4806         if (temp > 127)
4807                 temp -= 256;
4808         pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4809
4810         pi_lcn->lcnphy_Med_Low_Gain_db =
4811                 (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
4812         pi_lcn->lcnphy_Very_Low_Gain_db =
4813                 (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
4814
4815         tab.tbl_ptr = tableBuffer;
4816         tab.tbl_len = 2;
4817         tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4818         tab.tbl_offset = 28;
4819         tab.tbl_width = 32;
4820         wlc_lcnphy_read_table(pi, &tab);
4821
4822         pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4823         pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4824
4825 }
4826
4827 static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
4828 {
4829
4830         wlc_lcnphy_tbl_init(pi);
4831         wlc_lcnphy_rev0_baseband_init(pi);
4832         if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4833                 wlc_lcnphy_rev2_baseband_init(pi);
4834         wlc_lcnphy_bu_tweaks(pi);
4835 }
4836
4837 void wlc_phy_init_lcnphy(struct brcms_phy *pi)
4838 {
4839         u8 phybw40;
4840         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4841         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4842
4843         pi_lcn->lcnphy_cal_counter = 0;
4844         pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
4845
4846         or_phy_reg(pi, 0x44a, 0x80);
4847         and_phy_reg(pi, 0x44a, 0x7f);
4848
4849         wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
4850
4851         write_phy_reg(pi, 0x60a, 160);
4852
4853         write_phy_reg(pi, 0x46a, 25);
4854
4855         wlc_lcnphy_baseband_init(pi);
4856
4857         wlc_lcnphy_radio_init(pi);
4858
4859         if (CHSPEC_IS2G(pi->radio_chanspec))
4860                 wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
4861
4862         wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
4863
4864         bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9);
4865
4866         bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0,
4867                                     0x03CDDDDD);
4868
4869         if ((pi->sh->boardflags & BFL_FEM)
4870             && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4871                 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
4872
4873         wlc_lcnphy_agc_temp_init(pi);
4874
4875         wlc_lcnphy_temp_adj(pi);
4876
4877         mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4878
4879         udelay(100);
4880         mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4881
4882         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
4883         pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
4884         wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
4885 }
4886
4887 static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
4888 {
4889         s8 txpwr = 0;
4890         int i;
4891         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4892         struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
4893
4894         if (CHSPEC_IS2G(pi->radio_chanspec)) {
4895                 u16 cckpo = 0;
4896                 u32 offset_ofdm, offset_mcs;
4897
4898                 pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
4899
4900                 pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
4901
4902                 pi->txpa_2g[0] = sprom->pa0b0;
4903                 pi->txpa_2g[1] = sprom->pa0b1;
4904                 pi->txpa_2g[2] = sprom->pa0b2;
4905
4906                 pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
4907                 pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
4908                 pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
4909
4910                 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4911                 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4912                 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4913
4914                 pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
4915                 pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
4916                 pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
4917
4918                 txpwr = sprom->core_pwr_info[0].maxpwr_2g;
4919                 pi->tx_srom_max_2g = txpwr;
4920
4921                 for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4922                         pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4923                         pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4924                 }
4925
4926                 cckpo = sprom->cck2gpo;
4927                 offset_ofdm = sprom->ofdm2gpo;
4928                 if (cckpo) {
4929                         uint max_pwr_chan = txpwr;
4930
4931                         for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4932                                 pi->tx_srom_max_rate_2g[i] =
4933                                         max_pwr_chan - ((cckpo & 0xf) * 2);
4934                                 cckpo >>= 4;
4935                         }
4936
4937                         for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4938                                 pi->tx_srom_max_rate_2g[i] =
4939                                         max_pwr_chan -
4940                                         ((offset_ofdm & 0xf) * 2);
4941                                 offset_ofdm >>= 4;
4942                         }
4943                 } else {
4944                         u8 opo = 0;
4945
4946                         opo = sprom->opo;
4947
4948                         for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
4949                                 pi->tx_srom_max_rate_2g[i] = txpwr;
4950
4951                         for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4952                                 pi->tx_srom_max_rate_2g[i] = txpwr -
4953                                                 ((offset_ofdm & 0xf) * 2);
4954                                 offset_ofdm >>= 4;
4955                         }
4956                         offset_mcs = sprom->mcs2gpo[1] << 16;
4957                         offset_mcs |= sprom->mcs2gpo[0];
4958                         pi_lcn->lcnphy_mcs20_po = offset_mcs;
4959                         for (i = TXP_FIRST_SISO_MCS_20;
4960                              i <= TXP_LAST_SISO_MCS_20; i++) {
4961                                 pi->tx_srom_max_rate_2g[i] =
4962                                         txpwr - ((offset_mcs & 0xf) * 2);
4963                                 offset_mcs >>= 4;
4964                         }
4965                 }
4966
4967                 pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
4968                 pi_lcn->lcnphy_measPower = sprom->measpower;
4969                 pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
4970                 pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
4971                 pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
4972                 pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
4973                 pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
4974                 pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
4975                 if (sprom->ant_available_bg > 1)
4976                         wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
4977                                 sprom->ant_available_bg);
4978         }
4979         pi_lcn->lcnphy_cck_dig_filt_type = -1;
4980
4981         return true;
4982 }
4983
4984 void wlc_2064_vco_cal(struct brcms_phy *pi)
4985 {
4986         u8 calnrst;
4987
4988         mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4989         calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4990         write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4991         udelay(1);
4992         write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4993         udelay(1);
4994         write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4995         udelay(300);
4996         mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4997 }
4998
4999 bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
5000 {
5001         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
5002                 return false;
5003         else
5004                 return (LCNPHY_TX_PWR_CTRL_HW ==
5005                         wlc_lcnphy_get_tx_pwr_ctrl((pi)));
5006 }
5007
5008 void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
5009 {
5010         u16 pwr_ctrl;
5011         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5012                 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5013         } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
5014                 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
5015                 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
5016                 wlc_lcnphy_txpower_recalc_target(pi);
5017                 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5018         }
5019 }
5020
5021 void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
5022 {
5023         u8 channel = CHSPEC_CHANNEL(chanspec);
5024
5025         wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec);
5026
5027         wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
5028
5029         or_phy_reg(pi, 0x44a, 0x44);
5030         write_phy_reg(pi, 0x44a, 0x80);
5031
5032         wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
5033         udelay(1000);
5034
5035         wlc_lcnphy_toggle_afe_pwdn(pi);
5036
5037         write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
5038         write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
5039
5040         if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
5041                 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
5042
5043                 wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
5044         } else {
5045                 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
5046
5047                 wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
5048         }
5049
5050         if (pi->sh->boardflags & BFL_FEM)
5051                 wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
5052         else
5053                 wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
5054
5055         mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
5056         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
5057                 wlc_lcnphy_tssi_setup(pi);
5058 }
5059
5060 void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
5061 {
5062         kfree(pi->u.pi_lcnphy);
5063 }
5064
5065 bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
5066 {
5067         struct brcms_phy_lcnphy *pi_lcn;
5068
5069         pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
5070         if (pi->u.pi_lcnphy == NULL)
5071                 return false;
5072
5073         pi_lcn = pi->u.pi_lcnphy;
5074
5075         if (0 == (pi->sh->boardflags & BFL_NOPA)) {
5076                 pi->hwpwrctrl = true;
5077                 pi->hwpwrctrl_capable = true;
5078         }
5079
5080         pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc);
5081         pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5082
5083         pi->pi_fptr.init = wlc_phy_init_lcnphy;
5084         pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5085         pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5086         pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5087         pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5088         pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5089         pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5090         pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5091         pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5092
5093         if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5094                 return false;
5095
5096         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5097                 if (pi_lcn->lcnphy_tempsense_option == 3) {
5098                         pi->hwpwrctrl = true;
5099                         pi->hwpwrctrl_capable = true;
5100                         pi->temppwrctrl_capable = false;
5101                 } else {
5102                         pi->hwpwrctrl = false;
5103                         pi->hwpwrctrl_capable = false;
5104                         pi->temppwrctrl_capable = true;
5105                 }
5106         }
5107
5108         return true;
5109 }
5110
5111 static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
5112 {
5113         u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5114
5115         trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5116         ext_lna = (u16) (gain >> 29) & 0x01;
5117         lna1 = (u16) (gain >> 0) & 0x0f;
5118         lna2 = (u16) (gain >> 4) & 0x0f;
5119         tia = (u16) (gain >> 8) & 0xf;
5120         biq0 = (u16) (gain >> 12) & 0xf;
5121         biq1 = (u16) (gain >> 16) & 0xf;
5122
5123         gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5124                           ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5125                           ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5126         gain16_19 = biq1;
5127
5128         mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5129         mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5130         mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5131         mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5132         mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5133
5134         if (CHSPEC_IS2G(pi->radio_chanspec)) {
5135                 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5136                 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5137         }
5138         wlc_lcnphy_rx_gain_override_enable(pi, true);
5139 }
5140
5141 static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
5142 {
5143         u32 received_power = 0;
5144         s32 max_index = 0;
5145         u32 gain_code = 0;
5146         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5147
5148         max_index = 36;
5149         if (*gain_index >= 0)
5150                 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5151
5152         if (-1 == *gain_index) {
5153                 *gain_index = 0;
5154                 while ((*gain_index <= (s32) max_index)
5155                        && (received_power < 700)) {
5156                         wlc_lcnphy_set_rx_gain(pi,
5157                                                lcnphy_23bitgaincode_table
5158                                                [*gain_index]);
5159                         received_power =
5160                                 wlc_lcnphy_measure_digital_power(
5161                                         pi,
5162                                         pi_lcn->
5163                                         lcnphy_noise_samples);
5164                         (*gain_index)++;
5165                 }
5166                 (*gain_index)--;
5167         } else {
5168                 wlc_lcnphy_set_rx_gain(pi, gain_code);
5169                 received_power =
5170                         wlc_lcnphy_measure_digital_power(pi,
5171                                                          pi_lcn->
5172                                                          lcnphy_noise_samples);
5173         }
5174
5175         return received_power;
5176 }
5177
5178 s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
5179 {
5180         s32 gain = 0;
5181         s32 nominal_power_db;
5182         s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5183             input_power_db;
5184         s32 received_power, temperature;
5185         u32 power;
5186         u32 msb1, msb2, val1, val2, diff1, diff2;
5187         uint freq;
5188         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5189
5190         received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5191
5192         gain = lcnphy_gain_table[gain_index];
5193
5194         nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5195
5196         power = (received_power * 16);
5197         msb1 = ffs(power) - 1;
5198         msb2 = msb1 + 1;
5199         val1 = 1 << msb1;
5200         val2 = 1 << msb2;
5201         diff1 = (power - val1);
5202         diff2 = (val2 - power);
5203         if (diff1 < diff2)
5204                 log_val = msb1;
5205         else
5206                 log_val = msb2;
5207
5208         log_val = log_val * 3;
5209
5210         gain_mismatch = (nominal_power_db / 2) - (log_val);
5211
5212         desired_gain = gain + gain_mismatch;
5213
5214         input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5215
5216         if (input_power_offset_db > 127)
5217                 input_power_offset_db -= 256;
5218
5219         input_power_db = input_power_offset_db - desired_gain;
5220
5221         input_power_db =
5222                 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5223
5224         freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5225         if ((freq > 2427) && (freq <= 2467))
5226                 input_power_db = input_power_db - 1;
5227
5228         temperature = pi_lcn->lcnphy_lastsensed_temperature;
5229
5230         if ((temperature - 15) < -30)
5231                 input_power_db =
5232                         input_power_db +
5233                         (((temperature - 10 - 25) * 286) >> 12) -
5234                         7;
5235         else if ((temperature - 15) < 4)
5236                 input_power_db =
5237                         input_power_db +
5238                         (((temperature - 10 - 25) * 286) >> 12) -
5239                         3;
5240         else
5241                 input_power_db = input_power_db +
5242                                         (((temperature - 10 - 25) * 286) >> 12);
5243
5244         wlc_lcnphy_rx_gain_override_enable(pi, 0);
5245
5246         return input_power_db;
5247 }