GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / net / wireless / broadcom / 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_array(131, sizeof(s16), 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_array(20, sizeof(u16), 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         mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3392         mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3393
3394         if (phybw40 == 0) {
3395                 mod_phy_reg((pi), 0x410,
3396                             (0x1 << 6) |
3397                             (0x1 << 5),
3398                             ((CHSPEC_IS2G(
3399                                       pi->radio_chanspec)) ? (!mode) : 0) <<
3400                             6 | (!mode) << 5);
3401                 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
3402         }
3403 }
3404
3405 void
3406 wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
3407                          bool iqcalmode)
3408 {
3409         u8 phy_bw;
3410         u16 num_samps, t, k;
3411         u32 bw;
3412         s32 theta = 0, rot = 0;
3413         struct cordic_iq tone_samp;
3414         u32 data_buf[64];
3415         u16 i_samp, q_samp;
3416         struct phytbl_info tab;
3417         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3418
3419         pi->phy_tx_tone_freq = f_kHz;
3420
3421         wlc_lcnphy_deaf_mode(pi, true);
3422
3423         phy_bw = 40;
3424         if (pi_lcn->lcnphy_spurmod) {
3425                 write_phy_reg(pi, 0x942, 0x2);
3426                 write_phy_reg(pi, 0x93b, 0x0);
3427                 write_phy_reg(pi, 0x93c, 0x0);
3428                 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3429         }
3430
3431         if (f_kHz) {
3432                 k = 1;
3433                 do {
3434                         bw = phy_bw * 1000 * k;
3435                         num_samps = bw / abs(f_kHz);
3436                         k++;
3437                 } while ((num_samps * (u32) (abs(f_kHz))) != bw);
3438         } else
3439                 num_samps = 2;
3440
3441         rot = ((f_kHz * 36) / phy_bw) / 100;
3442         theta = 0;
3443
3444         for (t = 0; t < num_samps; t++) {
3445
3446                 tone_samp = cordic_calc_iq(theta);
3447
3448                 theta += rot;
3449
3450                 i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
3451                 q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
3452                 data_buf[t] = (i_samp << 10) | q_samp;
3453         }
3454
3455         mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
3456
3457         mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
3458
3459         tab.tbl_ptr = data_buf;
3460         tab.tbl_len = num_samps;
3461         tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
3462         tab.tbl_offset = 0;
3463         tab.tbl_width = 32;
3464         wlc_lcnphy_write_table(pi, &tab);
3465
3466         wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
3467 }
3468
3469 void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
3470 {
3471         s16 playback_status;
3472         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3473
3474         pi->phy_tx_tone_freq = 0;
3475         if (pi_lcn->lcnphy_spurmod) {
3476                 write_phy_reg(pi, 0x942, 0x7);
3477                 write_phy_reg(pi, 0x93b, 0x2017);
3478                 write_phy_reg(pi, 0x93c, 0x27c5);
3479                 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3480         }
3481
3482         playback_status = read_phy_reg(pi, 0x644);
3483         if (playback_status & (0x1 << 0)) {
3484                 wlc_lcnphy_tx_pu(pi, 0);
3485                 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
3486         } else if (playback_status & (0x1 << 1))
3487                 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
3488
3489         mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
3490
3491         mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
3492
3493         mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
3494
3495         and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
3496
3497         wlc_lcnphy_deaf_mode(pi, false);
3498 }
3499
3500 static void
3501 wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3502 {
3503         u16 di0dq0;
3504         u16 x, y, data_rf;
3505         int k;
3506         switch (cal_type) {
3507         case 0:
3508                 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3509                 break;
3510         case 2:
3511                 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3512                 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3513                 break;
3514         case 3:
3515                 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3516                 y = 8 + k;
3517                 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3518                 x = 8 - k;
3519                 data_rf = (x * 16 + y);
3520                 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3521                 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3522                 y = 8 + k;
3523                 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3524                 x = 8 - k;
3525                 data_rf = (x * 16 + y);
3526                 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3527                 break;
3528         case 4:
3529                 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3530                 y = 8 + k;
3531                 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3532                 x = 8 - k;
3533                 data_rf = (x * 16 + y);
3534                 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3535                 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3536                 y = 8 + k;
3537                 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3538                 x = 8 - k;
3539                 data_rf = (x * 16 + y);
3540                 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3541                 break;
3542         }
3543 }
3544
3545 static struct lcnphy_unsign16_struct
3546 wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
3547 {
3548         u16 a, b, didq;
3549         u8 di0, dq0, ei, eq, fi, fq;
3550         struct lcnphy_unsign16_struct cc;
3551         cc.re = 0;
3552         cc.im = 0;
3553         switch (cal_type) {
3554         case 0:
3555                 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3556                 cc.re = a;
3557                 cc.im = b;
3558                 break;
3559         case 2:
3560                 didq = wlc_lcnphy_get_tx_locc(pi);
3561                 di0 = (((didq & 0xff00) << 16) >> 24);
3562                 dq0 = (((didq & 0x00ff) << 24) >> 24);
3563                 cc.re = (u16) di0;
3564                 cc.im = (u16) dq0;
3565                 break;
3566         case 3:
3567                 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3568                 cc.re = (u16) ei;
3569                 cc.im = (u16) eq;
3570                 break;
3571         case 4:
3572                 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3573                 cc.re = (u16) fi;
3574                 cc.im = (u16) fq;
3575                 break;
3576         }
3577         return cc;
3578 }
3579
3580 static void
3581 wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
3582                     s16 *ptr, int mode)
3583 {
3584         u32 curval1, curval2, stpptr, curptr, strptr, val;
3585         u16 sslpnCalibClkEnCtrl, timer;
3586         u16 old_sslpnCalibClkEnCtrl;
3587         s16 imag, real;
3588         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3589
3590         timer = 0;
3591         old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3592
3593         curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));
3594         ptr[130] = 0;
3595         bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),
3596                      ((1 << 6) | curval1));
3597
3598         bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);
3599         bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);
3600         udelay(20);
3601         curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));
3602         bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),
3603                      curval2 | 0x30);
3604
3605         write_phy_reg(pi, 0x555, 0x0);
3606         write_phy_reg(pi, 0x5a6, 0x5);
3607
3608         write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3609         write_phy_reg(pi, 0x5cf, 3);
3610         write_phy_reg(pi, 0x5a5, 0x3);
3611         write_phy_reg(pi, 0x583, 0x0);
3612         write_phy_reg(pi, 0x584, 0x0);
3613         write_phy_reg(pi, 0x585, 0x0fff);
3614         write_phy_reg(pi, 0x586, 0x0000);
3615
3616         write_phy_reg(pi, 0x580, 0x4501);
3617
3618         sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3619         write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3620         stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));
3621         curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3622         do {
3623                 udelay(10);
3624                 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3625                 timer++;
3626         } while ((curptr != stpptr) && (timer < 500));
3627
3628         bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);
3629         strptr = 0x7E00;
3630         bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);
3631         while (strptr < 0x8000) {
3632                 val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));
3633                 imag = ((val >> 16) & 0x3ff);
3634                 real = ((val) & 0x3ff);
3635                 if (imag > 511)
3636                         imag -= 1024;
3637
3638                 if (real > 511)
3639                         real -= 1024;
3640
3641                 if (pi_lcn->lcnphy_iqcal_swp_dis)
3642                         ptr[(strptr - 0x7E00) / 4] = real;
3643                 else
3644                         ptr[(strptr - 0x7E00) / 4] = imag;
3645
3646                 if (clip_detect_algo) {
3647                         if (imag > thresh || imag < -thresh) {
3648                                 strptr = 0x8000;
3649                                 ptr[130] = 1;
3650                         }
3651                 }
3652
3653                 strptr += 4;
3654         }
3655
3656         write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3657         bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);
3658         bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);
3659 }
3660
3661 static void
3662 wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
3663               int step_size_lg2)
3664 {
3665         const struct lcnphy_spb_tone *phy_c1;
3666         struct lcnphy_spb_tone phy_c2;
3667         struct lcnphy_unsign16_struct phy_c3;
3668         int phy_c4, phy_c5, k, l, j, phy_c6;
3669         u16 phy_c7, phy_c8, phy_c9;
3670         s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
3671         s16 *ptr, phy_c17;
3672         s32 phy_c18, phy_c19;
3673         u32 phy_c20, phy_c21;
3674         bool phy_c22, phy_c23, phy_c24, phy_c25;
3675         u16 phy_c26, phy_c27;
3676         u16 phy_c28, phy_c29, phy_c30;
3677         u16 phy_c31;
3678         u16 *phy_c32;
3679         phy_c21 = 0;
3680         phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
3681         ptr = kmalloc_array(131, sizeof(s16), GFP_ATOMIC);
3682         if (NULL == ptr)
3683                 return;
3684
3685         phy_c32 = kmalloc_array(20, sizeof(u16), GFP_ATOMIC);
3686         if (NULL == phy_c32) {
3687                 kfree(ptr);
3688                 return;
3689         }
3690         phy_c26 = read_phy_reg(pi, 0x6da);
3691         phy_c27 = read_phy_reg(pi, 0x6db);
3692         phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
3693         write_phy_reg(pi, 0x93d, 0xC0);
3694
3695         wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
3696         write_phy_reg(pi, 0x6da, 0xffff);
3697         or_phy_reg(pi, 0x6db, 0x3);
3698
3699         wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
3700         udelay(500);
3701         phy_c28 = read_phy_reg(pi, 0x938);
3702         phy_c29 = read_phy_reg(pi, 0x4d7);
3703         phy_c30 = read_phy_reg(pi, 0x4d8);
3704         or_phy_reg(pi, 0x938, 0x1 << 2);
3705         or_phy_reg(pi, 0x4d7, 0x1 << 2);
3706         or_phy_reg(pi, 0x4d7, 0x1 << 3);
3707         mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
3708         or_phy_reg(pi, 0x4d8, 1 << 0);
3709         or_phy_reg(pi, 0x4d8, 1 << 1);
3710         mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
3711         mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
3712         phy_c1 = &lcnphy_spb_tone_3750[0];
3713         phy_c4 = 32;
3714
3715         if (num_levels == 0) {
3716                 if (cal_type != 0)
3717                         num_levels = 4;
3718                 else
3719                         num_levels = 9;
3720         }
3721         if (step_size_lg2 == 0) {
3722                 if (cal_type != 0)
3723                         step_size_lg2 = 3;
3724                 else
3725                         step_size_lg2 = 8;
3726         }
3727
3728         phy_c7 = (1 << step_size_lg2);
3729         phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
3730         phy_c15 = (s16) phy_c3.re;
3731         phy_c16 = (s16) phy_c3.im;
3732         if (cal_type == 2) {
3733                 if (phy_c3.re > 127)
3734                         phy_c15 = phy_c3.re - 256;
3735                 if (phy_c3.im > 127)
3736                         phy_c16 = phy_c3.im - 256;
3737         }
3738         wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3739         udelay(20);
3740         for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
3741                 phy_c23 = true;
3742                 phy_c22 = false;
3743                 switch (cal_type) {
3744                 case 0:
3745                         phy_c10 = 511;
3746                         break;
3747                 case 2:
3748                         phy_c10 = 127;
3749                         break;
3750                 case 3:
3751                         phy_c10 = 15;
3752                         break;
3753                 case 4:
3754                         phy_c10 = 15;
3755                         break;
3756                 }
3757
3758                 phy_c9 = read_phy_reg(pi, 0x93d);
3759                 phy_c9 = 2 * phy_c9;
3760                 phy_c24 = false;
3761                 phy_c5 = 7;
3762                 phy_c25 = true;
3763                 while (1) {
3764                         write_radio_reg(pi, RADIO_2064_REG026,
3765                                         (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
3766                         udelay(50);
3767                         phy_c22 = false;
3768                         ptr[130] = 0;
3769                         wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
3770                         if (ptr[130] == 1)
3771                                 phy_c22 = true;
3772                         if (phy_c22)
3773                                 phy_c5 -= 1;
3774                         if ((phy_c22 != phy_c24) && (!phy_c25))
3775                                 break;
3776                         if (!phy_c22)
3777                                 phy_c5 += 1;
3778                         if (phy_c5 <= 0 || phy_c5 >= 7)
3779                                 break;
3780                         phy_c24 = phy_c22;
3781                         phy_c25 = false;
3782                 }
3783
3784                 if (phy_c5 < 0)
3785                         phy_c5 = 0;
3786                 else if (phy_c5 > 7)
3787                         phy_c5 = 7;
3788
3789                 for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
3790                         for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
3791                                 phy_c11 = phy_c15 + k;
3792                                 phy_c12 = phy_c16 + l;
3793
3794                                 if (phy_c11 < -phy_c10)
3795                                         phy_c11 = -phy_c10;
3796                                 else if (phy_c11 > phy_c10)
3797                                         phy_c11 = phy_c10;
3798                                 if (phy_c12 < -phy_c10)
3799                                         phy_c12 = -phy_c10;
3800                                 else if (phy_c12 > phy_c10)
3801                                         phy_c12 = phy_c10;
3802                                 wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
3803                                                   phy_c12);
3804                                 udelay(20);
3805                                 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
3806
3807                                 phy_c18 = 0;
3808                                 phy_c19 = 0;
3809                                 for (j = 0; j < 128; j++) {
3810                                         if (cal_type != 0)
3811                                                 phy_c6 = j % phy_c4;
3812                                         else
3813                                                 phy_c6 = (2 * j) % phy_c4;
3814
3815                                         phy_c2.re = phy_c1[phy_c6].re;
3816                                         phy_c2.im = phy_c1[phy_c6].im;
3817                                         phy_c17 = ptr[j];
3818                                         phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
3819                                         phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
3820                                 }
3821
3822                                 phy_c18 = phy_c18 >> 10;
3823                                 phy_c19 = phy_c19 >> 10;
3824                                 phy_c20 = ((phy_c18 * phy_c18) +
3825                                            (phy_c19 * phy_c19));
3826
3827                                 if (phy_c23 || phy_c20 < phy_c21) {
3828                                         phy_c21 = phy_c20;
3829                                         phy_c13 = phy_c11;
3830                                         phy_c14 = phy_c12;
3831                                 }
3832                                 phy_c23 = false;
3833                         }
3834                 }
3835                 phy_c23 = true;
3836                 phy_c15 = phy_c13;
3837                 phy_c16 = phy_c14;
3838                 phy_c7 = phy_c7 >> 1;
3839                 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3840                 udelay(20);
3841         }
3842         goto cleanup;
3843 cleanup:
3844         wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
3845         wlc_lcnphy_stop_tx_tone(pi);
3846         write_phy_reg(pi, 0x6da, phy_c26);
3847         write_phy_reg(pi, 0x6db, phy_c27);
3848         write_phy_reg(pi, 0x938, phy_c28);
3849         write_phy_reg(pi, 0x4d7, phy_c29);
3850         write_phy_reg(pi, 0x4d8, phy_c30);
3851         write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
3852
3853         kfree(phy_c32);
3854         kfree(ptr);
3855 }
3856
3857 void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
3858 {
3859         u16 iqcc[2];
3860         struct phytbl_info tab;
3861
3862         tab.tbl_ptr = iqcc;
3863         tab.tbl_len = 2;
3864         tab.tbl_id = 0;
3865         tab.tbl_offset = 80;
3866         tab.tbl_width = 16;
3867         wlc_lcnphy_read_table(pi, &tab);
3868
3869         *a = iqcc[0];
3870         *b = iqcc[1];
3871 }
3872
3873 static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
3874 {
3875         struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3876
3877         wlc_lcnphy_set_cc(pi, 0, 0, 0);
3878         wlc_lcnphy_set_cc(pi, 2, 0, 0);
3879         wlc_lcnphy_set_cc(pi, 3, 0, 0);
3880         wlc_lcnphy_set_cc(pi, 4, 0, 0);
3881
3882         wlc_lcnphy_a1(pi, 4, 0, 0);
3883         wlc_lcnphy_a1(pi, 3, 0, 0);
3884         wlc_lcnphy_a1(pi, 2, 3, 2);
3885         wlc_lcnphy_a1(pi, 0, 5, 8);
3886         wlc_lcnphy_a1(pi, 2, 2, 1);
3887         wlc_lcnphy_a1(pi, 0, 4, 3);
3888
3889         iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3890         locc2 = wlc_lcnphy_get_cc(pi, 2);
3891         locc3 = wlc_lcnphy_get_cc(pi, 3);
3892         locc4 = wlc_lcnphy_get_cc(pi, 4);
3893 }
3894
3895 u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
3896 {
3897         struct phytbl_info tab;
3898         u16 didq;
3899
3900         tab.tbl_id = 0;
3901         tab.tbl_width = 16;
3902         tab.tbl_ptr = &didq;
3903         tab.tbl_len = 1;
3904         tab.tbl_offset = 85;
3905         wlc_lcnphy_read_table(pi, &tab);
3906
3907         return didq;
3908 }
3909
3910 static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
3911 {
3912
3913         struct lcnphy_txgains target_gains, old_gains;
3914         u8 save_bb_mult;
3915         u16 a, b, didq, save_pa_gain = 0;
3916         uint idx, SAVE_txpwrindex = 0xFF;
3917         u32 val;
3918         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3919         struct phytbl_info tab;
3920         u8 ei0, eq0, fi0, fq0;
3921         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3922
3923         wlc_lcnphy_get_tx_gain(pi, &old_gains);
3924         save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
3925
3926         save_bb_mult = wlc_lcnphy_get_bbmult(pi);
3927
3928         if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
3929                 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
3930
3931         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3932
3933         target_gains.gm_gain = 7;
3934         target_gains.pga_gain = 0;
3935         target_gains.pad_gain = 21;
3936         target_gains.dac_gain = 0;
3937         wlc_lcnphy_set_tx_gain(pi, &target_gains);
3938
3939         if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
3940
3941                 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
3942
3943                 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3944                                        (pi_lcn->
3945                                         lcnphy_recal ? LCNPHY_CAL_RECAL :
3946                                         LCNPHY_CAL_FULL), false);
3947         } else {
3948                 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3949                 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3950         }
3951
3952         wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
3953         if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
3954                 if (CHSPEC_IS5G(pi->radio_chanspec)) {
3955                         target_gains.gm_gain = 255;
3956                         target_gains.pga_gain = 255;
3957                         target_gains.pad_gain = 0xf0;
3958                         target_gains.dac_gain = 0;
3959                 } else {
3960                         target_gains.gm_gain = 7;
3961                         target_gains.pga_gain = 45;
3962                         target_gains.pad_gain = 186;
3963                         target_gains.dac_gain = 0;
3964                 }
3965
3966                 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
3967                     || pi_lcn->lcnphy_hw_iqcal_en) {
3968
3969                         target_gains.pga_gain = 0;
3970                         target_gains.pad_gain = 30;
3971                         wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3972                         wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3973                                                LCNPHY_CAL_FULL, false);
3974                 } else {
3975                         wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3976                 }
3977         }
3978
3979         wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3980
3981         didq = wlc_lcnphy_get_tx_locc(pi);
3982
3983         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3984         tab.tbl_width = 32;
3985         tab.tbl_ptr = &val;
3986
3987         tab.tbl_len = 1;
3988         tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
3989
3990         for (idx = 0; idx < 128; idx++) {
3991                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
3992
3993                 wlc_lcnphy_read_table(pi, &tab);
3994                 val = (val & 0xfff00000) |
3995                       ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
3996                 wlc_lcnphy_write_table(pi, &tab);
3997
3998                 val = didq;
3999                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
4000                 wlc_lcnphy_write_table(pi, &tab);
4001         }
4002
4003         pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
4004         pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
4005         pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
4006         pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
4007         pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
4008         pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
4009         pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
4010
4011         wlc_lcnphy_set_bbmult(pi, save_bb_mult);
4012         wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
4013         wlc_lcnphy_set_tx_gain(pi, &old_gains);
4014
4015         if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
4016                 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4017         else
4018                 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
4019 }
4020
4021 s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
4022 {
4023         u16 tempsenseval1, tempsenseval2;
4024         s16 avg = 0;
4025         bool suspend = false;
4026
4027         if (mode == 1) {
4028                 suspend = (0 == (bcma_read32(pi->d11core,
4029                                              D11REGOFFS(maccontrol)) &
4030                                  MCTL_EN_MAC));
4031                 if (!suspend)
4032                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
4033                 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4034         }
4035         tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4036         tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4037
4038         if (tempsenseval1 > 255)
4039                 avg = (s16) (tempsenseval1 - 512);
4040         else
4041                 avg = (s16) tempsenseval1;
4042
4043         if (tempsenseval2 > 255)
4044                 avg += (s16) (tempsenseval2 - 512);
4045         else
4046                 avg += (s16) tempsenseval2;
4047
4048         avg /= 2;
4049
4050         if (mode == 1) {
4051
4052                 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4053
4054                 udelay(100);
4055                 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4056
4057                 if (!suspend)
4058                         wlapi_enable_mac(pi->sh->physhim);
4059         }
4060         return avg;
4061 }
4062
4063 u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
4064 {
4065         u16 tempsenseval1, tempsenseval2;
4066         s32 avg = 0;
4067         bool suspend = false;
4068         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4069         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4070
4071         if (mode == 1) {
4072                 suspend = (0 == (bcma_read32(pi->d11core,
4073                                              D11REGOFFS(maccontrol)) &
4074                                  MCTL_EN_MAC));
4075                 if (!suspend)
4076                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
4077                 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4078         }
4079         tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4080         tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4081
4082         if (tempsenseval1 > 255)
4083                 avg = (int)(tempsenseval1 - 512);
4084         else
4085                 avg = (int)tempsenseval1;
4086
4087         if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
4088                 if (tempsenseval2 > 255)
4089                         avg = (int)(avg - tempsenseval2 + 512);
4090                 else
4091                         avg = (int)(avg - tempsenseval2);
4092         } else {
4093                 if (tempsenseval2 > 255)
4094                         avg = (int)(avg + tempsenseval2 - 512);
4095                 else
4096                         avg = (int)(avg + tempsenseval2);
4097                 avg = avg / 2;
4098         }
4099         if (avg < 0)
4100                 avg = avg + 512;
4101
4102         if (pi_lcn->lcnphy_tempsense_option == 2)
4103                 avg = tempsenseval1;
4104
4105         if (mode)
4106                 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4107
4108         if (mode == 1) {
4109
4110                 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4111
4112                 udelay(100);
4113                 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4114
4115                 if (!suspend)
4116                         wlapi_enable_mac(pi->sh->physhim);
4117         }
4118         return (u16) avg;
4119 }
4120
4121 s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
4122 {
4123         s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
4124         degree =
4125                 ((degree <<
4126                   10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
4127                 / LCN_TEMPSENSE_DEN;
4128         return (s8) degree;
4129 }
4130
4131 s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
4132 {
4133         u16 vbatsenseval;
4134         s32 avg = 0;
4135         bool suspend = false;
4136
4137         if (mode == 1) {
4138                 suspend = (0 == (bcma_read32(pi->d11core,
4139                                              D11REGOFFS(maccontrol)) &
4140                                  MCTL_EN_MAC));
4141                 if (!suspend)
4142                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
4143                 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
4144         }
4145
4146         vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
4147
4148         if (vbatsenseval > 255)
4149                 avg = (s32) (vbatsenseval - 512);
4150         else
4151                 avg = (s32) vbatsenseval;
4152
4153         avg =   (avg * LCN_VBAT_SCALE_NOM +
4154                  (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
4155
4156         if (mode == 1) {
4157                 if (!suspend)
4158                         wlapi_enable_mac(pi->sh->physhim);
4159         }
4160         return (s8) avg;
4161 }
4162
4163 static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
4164 {
4165         u8 phybw40;
4166         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4167
4168         mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
4169
4170         if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
4171             (mode == AFE_CLK_INIT_MODE_TXRX2X))
4172                 write_phy_reg(pi, 0x6d0, 0x7);
4173
4174         wlc_lcnphy_toggle_afe_pwdn(pi);
4175 }
4176
4177 static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4178 {
4179 }
4180
4181 static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
4182 {
4183         bool suspend;
4184         s8 index;
4185         u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4186         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4187         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4188                          MCTL_EN_MAC));
4189         if (!suspend)
4190                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4191         wlc_lcnphy_deaf_mode(pi, true);
4192         pi->phy_lastcal = pi->sh->now;
4193         pi->phy_forcecal = false;
4194         index = pi_lcn->lcnphy_current_index;
4195
4196         wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4197
4198         wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4199         wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4200         wlc_lcnphy_deaf_mode(pi, false);
4201         if (!suspend)
4202                 wlapi_enable_mac(pi->sh->physhim);
4203
4204 }
4205
4206 static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
4207 {
4208         bool suspend, full_cal;
4209         const struct lcnphy_rx_iqcomp *rx_iqcomp;
4210         int rx_iqcomp_sz;
4211         u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4212         s8 index;
4213         struct phytbl_info tab;
4214         s32 a1, b0, b1;
4215         s32 tssi, pwr, maxtargetpwr, mintargetpwr;
4216         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4217
4218         pi->phy_lastcal = pi->sh->now;
4219         pi->phy_forcecal = false;
4220         full_cal =
4221                 (pi_lcn->lcnphy_full_cal_channel !=
4222                  CHSPEC_CHANNEL(pi->radio_chanspec));
4223         pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
4224         index = pi_lcn->lcnphy_current_index;
4225
4226         suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4227                          MCTL_EN_MAC));
4228         if (!suspend) {
4229                 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
4230                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4231         }
4232
4233         wlc_lcnphy_deaf_mode(pi, true);
4234
4235         wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4236
4237         rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
4238         rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
4239
4240         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4241                 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
4242         else
4243                 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
4244
4245         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4246
4247                 wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
4248
4249                 b0 = pi->txpa_2g[0];
4250                 b1 = pi->txpa_2g[1];
4251                 a1 = pi->txpa_2g[2];
4252                 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
4253                 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
4254
4255                 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4256                 tab.tbl_width = 32;
4257                 tab.tbl_ptr = &pwr;
4258                 tab.tbl_len = 1;
4259                 tab.tbl_offset = 0;
4260                 for (tssi = 0; tssi < 128; tssi++) {
4261                         pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
4262                         pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
4263                         wlc_lcnphy_write_table(pi, &tab);
4264                         tab.tbl_offset++;
4265                 }
4266         }
4267
4268         wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4269         wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4270         wlc_lcnphy_deaf_mode(pi, false);
4271         if (!suspend)
4272                 wlapi_enable_mac(pi->sh->physhim);
4273 }
4274
4275 void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
4276 {
4277         u16 temp_new;
4278         int temp1, temp2, temp_diff;
4279         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4280
4281         switch (mode) {
4282         case PHY_PERICAL_CHAN:
4283                 break;
4284         case PHY_FULLCAL:
4285                 wlc_lcnphy_periodic_cal(pi);
4286                 break;
4287         case PHY_PERICAL_PHYINIT:
4288                 wlc_lcnphy_periodic_cal(pi);
4289                 break;
4290         case PHY_PERICAL_WATCHDOG:
4291                 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4292                         temp_new = wlc_lcnphy_tempsense(pi, 0);
4293                         temp1 = LCNPHY_TEMPSENSE(temp_new);
4294                         temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
4295                         temp_diff = temp1 - temp2;
4296                         if ((pi_lcn->lcnphy_cal_counter > 90) ||
4297                             (temp_diff > 60) || (temp_diff < -60)) {
4298                                 wlc_lcnphy_glacial_timer_based_cal(pi);
4299                                 wlc_2064_vco_cal(pi);
4300                                 pi_lcn->lcnphy_cal_temper = temp_new;
4301                                 pi_lcn->lcnphy_cal_counter = 0;
4302                         } else
4303                                 pi_lcn->lcnphy_cal_counter++;
4304                 }
4305                 break;
4306         case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
4307                 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4308                         wlc_lcnphy_tx_power_adjustment(
4309                                 (struct brcms_phy_pub *) pi);
4310                 break;
4311         }
4312 }
4313
4314 void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
4315 {
4316         s8 cck_offset;
4317         u16 status;
4318         status = (read_phy_reg(pi, 0x4ab));
4319         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
4320             (status  & (0x1 << 15))) {
4321                 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
4322                                    >> 0) >> 1);
4323
4324                 if (wlc_phy_tpc_isenabled_lcnphy(pi))
4325                         cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
4326                 else
4327                         cck_offset = 0;
4328
4329                 *cck_pwr = *ofdm_pwr + cck_offset;
4330         } else {
4331                 *cck_pwr = 0;
4332                 *ofdm_pwr = 0;
4333         }
4334 }
4335
4336 void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4337 {
4338         return;
4339
4340 }
4341
4342 void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
4343 {
4344         s8 index;
4345         u16 index2;
4346         struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
4347         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4348         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4349         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
4350             SAVE_txpwrctrl) {
4351                 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
4352                 index2 = (u16) (index * 2);
4353                 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
4354
4355                 pi_lcn->lcnphy_current_index =
4356                         (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
4357         }
4358 }
4359
4360 static void
4361 wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
4362                               const struct lcnphy_tx_gain_tbl_entry *gain_table)
4363 {
4364         u32 j;
4365         struct phytbl_info tab;
4366         u32 val;
4367         u16 pa_gain;
4368         u16 gm_gain;
4369
4370         if (pi->sh->boardflags & BFL_FEM)
4371                 pa_gain = 0x10;
4372         else
4373                 pa_gain = 0x60;
4374         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4375         tab.tbl_width = 32;
4376         tab.tbl_len = 1;
4377         tab.tbl_ptr = &val;
4378
4379         /* fixed gm_gain value for iPA */
4380         gm_gain = 15;
4381         for (j = 0; j < 128; j++) {
4382                 if (pi->sh->boardflags & BFL_FEM)
4383                         gm_gain = gain_table[j].gm;
4384                 val = (((u32) pa_gain << 24) |
4385                        (gain_table[j].pad << 16) |
4386                        (gain_table[j].pga << 8) | gm_gain);
4387
4388                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4389                 wlc_lcnphy_write_table(pi, &tab);
4390
4391                 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4392                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4393                 wlc_lcnphy_write_table(pi, &tab);
4394         }
4395 }
4396
4397 static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
4398 {
4399         struct phytbl_info tab;
4400         u32 val, bbmult, rfgain;
4401         u8 index;
4402         u8 scale_factor = 1;
4403         s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4404
4405         tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4406         tab.tbl_width = 32;
4407         tab.tbl_len = 1;
4408
4409         for (index = 0; index < 128; index++) {
4410                 tab.tbl_ptr = &bbmult;
4411                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4412                 wlc_lcnphy_read_table(pi, &tab);
4413                 bbmult = bbmult >> 20;
4414
4415                 tab.tbl_ptr = &rfgain;
4416                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4417                 wlc_lcnphy_read_table(pi, &tab);
4418
4419                 qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4420                 qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4421
4422                 if (qQ1 < qQ2) {
4423                         temp2 = qm_shr16(temp2, qQ2 - qQ1);
4424                         qQ = qQ1;
4425                 } else {
4426                         temp1 = qm_shr16(temp1, qQ1 - qQ2);
4427                         qQ = qQ2;
4428                 }
4429                 temp = qm_sub16(temp1, temp2);
4430
4431                 if (qQ >= 4)
4432                         shift = qQ - 4;
4433                 else
4434                         shift = 4 - qQ;
4435
4436                 val = (((index << shift) + (5 * temp) +
4437                         (1 << (scale_factor + shift - 3))) >> (scale_factor +
4438                                                                shift - 2));
4439
4440                 tab.tbl_ptr = &val;
4441                 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4442                 wlc_lcnphy_write_table(pi, &tab);
4443         }
4444 }
4445
4446 static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
4447 {
4448         or_phy_reg(pi, 0x805, 0x1);
4449
4450         mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4451
4452         mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4453
4454         write_phy_reg(pi, 0x414, 0x1e10);
4455         write_phy_reg(pi, 0x415, 0x0640);
4456
4457         mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4458
4459         or_phy_reg(pi, 0x44a, 0x44);
4460         write_phy_reg(pi, 0x44a, 0x80);
4461         mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4462
4463         mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4464
4465         if (!(pi->sh->boardrev < 0x1204))
4466                 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4467
4468         write_phy_reg(pi, 0x7d6, 0x0902);
4469         mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4470
4471         mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4472
4473         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4474                 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4475
4476                 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4477
4478                 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4479
4480                 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4481
4482                 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4483
4484                 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4485                 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4486                 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4487                 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4488                 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4489
4490                 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4491
4492                 wlc_lcnphy_clear_tx_power_offsets(pi);
4493                 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4494
4495         }
4496 }
4497
4498 static void wlc_lcnphy_rcal(struct brcms_phy *pi)
4499 {
4500         u8 rcal_value;
4501
4502         and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4503
4504         or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4505         or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4506
4507         or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4508         or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4509
4510         or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4511
4512         or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4513         mdelay(5);
4514         SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4515
4516         if (wlc_radio_2064_rcal_done(pi)) {
4517                 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4518                 rcal_value = rcal_value & 0x1f;
4519         }
4520
4521         and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4522
4523         and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4524 }
4525
4526 static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
4527 {
4528         u8 dflt_rc_cal_val;
4529         u16 flt_val;
4530
4531         dflt_rc_cal_val = 7;
4532         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4533                 dflt_rc_cal_val = 11;
4534         flt_val =
4535                 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4536                 (dflt_rc_cal_val);
4537         write_phy_reg(pi, 0x933, flt_val);
4538         write_phy_reg(pi, 0x934, flt_val);
4539         write_phy_reg(pi, 0x935, flt_val);
4540         write_phy_reg(pi, 0x936, flt_val);
4541         write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4542
4543         return;
4544 }
4545
4546 static void wlc_radio_2064_init(struct brcms_phy *pi)
4547 {
4548         u32 i;
4549         const struct lcnphy_radio_regs *lcnphyregs = NULL;
4550
4551         lcnphyregs = lcnphy_radio_regs_2064;
4552
4553         for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4554                 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4555                         write_radio_reg(pi,
4556                                         ((lcnphyregs[i].address & 0x3fff) |
4557                                          RADIO_DEFAULT_CORE),
4558                                         (u16) lcnphyregs[i].init_a);
4559                 else if (lcnphyregs[i].do_init_g)
4560                         write_radio_reg(pi,
4561                                         ((lcnphyregs[i].address & 0x3fff) |
4562                                          RADIO_DEFAULT_CORE),
4563                                         (u16) lcnphyregs[i].init_g);
4564
4565         write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4566         write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4567
4568         write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4569
4570         write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4571
4572         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4573
4574                 write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4575                 write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4576                 write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4577         }
4578
4579         write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4580         write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4581
4582         mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4583
4584         mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4585
4586         mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4587
4588         mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4589
4590         mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4591
4592         write_phy_reg(pi, 0x4ea, 0x4688);
4593
4594         if (pi->sh->boardflags & BFL_FEM)
4595                 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4596         else
4597                 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);
4598
4599         mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4600
4601         mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4602
4603         wlc_lcnphy_set_tx_locc(pi, 0);
4604
4605         wlc_lcnphy_rcal(pi);
4606
4607         wlc_lcnphy_rc_cal(pi);
4608
4609         if (!(pi->sh->boardflags & BFL_FEM)) {
4610                 write_radio_reg(pi, RADIO_2064_REG032, 0x6f);
4611                 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4612                 write_radio_reg(pi, RADIO_2064_REG039, 0xe);
4613         }
4614
4615 }
4616
4617 static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4618 {
4619         wlc_radio_2064_init(pi);
4620 }
4621
4622 static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
4623 {
4624         uint idx;
4625         u8 phybw40;
4626         struct phytbl_info tab;
4627         const struct phytbl_info *tb;
4628         u32 val;
4629
4630         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4631
4632         for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
4633                 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4634
4635         if (pi->sh->boardflags & BFL_FEM_BT) {
4636                 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4637                 tab.tbl_width = 16;
4638                 tab.tbl_ptr = &val;
4639                 tab.tbl_len = 1;
4640                 val = 100;
4641                 tab.tbl_offset = 4;
4642                 wlc_lcnphy_write_table(pi, &tab);
4643         }
4644
4645         if (!(pi->sh->boardflags & BFL_FEM)) {
4646                 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4647                 tab.tbl_width = 16;
4648                 tab.tbl_ptr = &val;
4649                 tab.tbl_len = 1;
4650
4651                 val = 150;
4652                 tab.tbl_offset = 0;
4653                 wlc_lcnphy_write_table(pi, &tab);
4654
4655                 val = 220;
4656                 tab.tbl_offset = 1;
4657                 wlc_lcnphy_write_table(pi, &tab);
4658         }
4659
4660         if (CHSPEC_IS2G(pi->radio_chanspec)) {
4661                 if (pi->sh->boardflags & BFL_FEM)
4662                         wlc_lcnphy_load_tx_gain_table(
4663                                 pi,
4664                                 dot11lcnphy_2GHz_extPA_gaintable_rev0);
4665                 else
4666                         wlc_lcnphy_load_tx_gain_table(
4667                                 pi,
4668                                 dot11lcnphy_2GHz_gaintable_rev0);
4669         }
4670
4671         if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4672                 int l;
4673
4674                 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4675                         l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4676                         if (pi->sh->boardflags & BFL_EXTLNA)
4677                                 tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
4678                         else
4679                                 tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
4680                 } else {
4681                         l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4682                         if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4683                                 tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
4684                         else
4685                                 tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
4686                 }
4687
4688                 for (idx = 0; idx < l; idx++)
4689                         wlc_lcnphy_write_table(pi, &tb[idx]);
4690         }
4691
4692         if (pi->sh->boardflags & BFL_FEM) {
4693                 if (pi->sh->boardflags & BFL_FEM_BT) {
4694                         if (pi->sh->boardrev < 0x1250)
4695                                 tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
4696                         else
4697                                 tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
4698                 } else {
4699                         tb = &dot11lcn_sw_ctrl_tbl_info_4313_epa;
4700                 }
4701         } else {
4702                 if (pi->sh->boardflags & BFL_FEM_BT)
4703                         tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa;
4704                 else
4705                         tb = &dot11lcn_sw_ctrl_tbl_info_4313;
4706         }
4707         wlc_lcnphy_write_table(pi, tb);
4708         wlc_lcnphy_load_rfpower(pi);
4709
4710         wlc_lcnphy_clear_papd_comptable(pi);
4711 }
4712
4713 static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
4714 {
4715         u16 afectrl1;
4716         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4717
4718         write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4719
4720         write_phy_reg(pi, 0x43b, 0x0);
4721         write_phy_reg(pi, 0x43c, 0x0);
4722         write_phy_reg(pi, 0x44c, 0x0);
4723         write_phy_reg(pi, 0x4e6, 0x0);
4724         write_phy_reg(pi, 0x4f9, 0x0);
4725         write_phy_reg(pi, 0x4b0, 0x0);
4726         write_phy_reg(pi, 0x938, 0x0);
4727         write_phy_reg(pi, 0x4b0, 0x0);
4728         write_phy_reg(pi, 0x44e, 0);
4729
4730         or_phy_reg(pi, 0x567, 0x03);
4731
4732         or_phy_reg(pi, 0x44a, 0x44);
4733         write_phy_reg(pi, 0x44a, 0x80);
4734
4735         if (!(pi->sh->boardflags & BFL_FEM))
4736                 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4737
4738         if (0) {
4739                 afectrl1 = 0;
4740                 afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4741                                   (pi_lcn->lcnphy_rssi_vc << 4) |
4742                                   (pi_lcn->lcnphy_rssi_gs << 10));
4743                 write_phy_reg(pi, 0x43e, afectrl1);
4744         }
4745
4746         mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4747         if (pi->sh->boardflags & BFL_FEM) {
4748                 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4749
4750                 write_phy_reg(pi, 0x910, 0x1);
4751         }
4752
4753         mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4754         mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4755         mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4756
4757 }
4758
4759 static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
4760 {
4761         if (CHSPEC_IS5G(pi->radio_chanspec)) {
4762                 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4763                 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4764         }
4765 }
4766
4767 static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
4768 {
4769         s16 temp;
4770         struct phytbl_info tab;
4771         u32 tableBuffer[2];
4772         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4773
4774         temp = (s16) read_phy_reg(pi, 0x4df);
4775         pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4776
4777         if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4778                 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4779
4780         pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4781
4782         if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4783                 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4784
4785         tab.tbl_ptr = tableBuffer;
4786         tab.tbl_len = 2;
4787         tab.tbl_id = 17;
4788         tab.tbl_offset = 59;
4789         tab.tbl_width = 32;
4790         wlc_lcnphy_read_table(pi, &tab);
4791
4792         if (tableBuffer[0] > 63)
4793                 tableBuffer[0] -= 128;
4794         pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4795
4796         if (tableBuffer[1] > 63)
4797                 tableBuffer[1] -= 128;
4798         pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4799
4800         temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
4801         if (temp > 127)
4802                 temp -= 256;
4803         pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4804
4805         pi_lcn->lcnphy_Med_Low_Gain_db =
4806                 (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
4807         pi_lcn->lcnphy_Very_Low_Gain_db =
4808                 (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
4809
4810         tab.tbl_ptr = tableBuffer;
4811         tab.tbl_len = 2;
4812         tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4813         tab.tbl_offset = 28;
4814         tab.tbl_width = 32;
4815         wlc_lcnphy_read_table(pi, &tab);
4816
4817         pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4818         pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4819
4820 }
4821
4822 static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
4823 {
4824
4825         wlc_lcnphy_tbl_init(pi);
4826         wlc_lcnphy_rev0_baseband_init(pi);
4827         if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4828                 wlc_lcnphy_rev2_baseband_init(pi);
4829         wlc_lcnphy_bu_tweaks(pi);
4830 }
4831
4832 void wlc_phy_init_lcnphy(struct brcms_phy *pi)
4833 {
4834         u8 phybw40;
4835         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4836         phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4837
4838         pi_lcn->lcnphy_cal_counter = 0;
4839         pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
4840
4841         or_phy_reg(pi, 0x44a, 0x80);
4842         and_phy_reg(pi, 0x44a, 0x7f);
4843
4844         wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
4845
4846         write_phy_reg(pi, 0x60a, 160);
4847
4848         write_phy_reg(pi, 0x46a, 25);
4849
4850         wlc_lcnphy_baseband_init(pi);
4851
4852         wlc_lcnphy_radio_init(pi);
4853
4854         if (CHSPEC_IS2G(pi->radio_chanspec))
4855                 wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
4856
4857         wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
4858
4859         bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9);
4860
4861         bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0,
4862                                     0x03CDDDDD);
4863
4864         if ((pi->sh->boardflags & BFL_FEM)
4865             && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4866                 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
4867
4868         wlc_lcnphy_agc_temp_init(pi);
4869
4870         wlc_lcnphy_temp_adj(pi);
4871
4872         mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4873
4874         udelay(100);
4875         mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4876
4877         wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
4878         pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
4879         wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
4880 }
4881
4882 static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
4883 {
4884         s8 txpwr = 0;
4885         int i;
4886         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4887         struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
4888
4889         if (CHSPEC_IS2G(pi->radio_chanspec)) {
4890                 u16 cckpo = 0;
4891                 u32 offset_ofdm, offset_mcs;
4892
4893                 pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
4894
4895                 pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
4896
4897                 pi->txpa_2g[0] = sprom->pa0b0;
4898                 pi->txpa_2g[1] = sprom->pa0b1;
4899                 pi->txpa_2g[2] = sprom->pa0b2;
4900
4901                 pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
4902                 pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
4903                 pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
4904
4905                 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4906                 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4907                 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4908
4909                 pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
4910                 pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
4911                 pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
4912
4913                 txpwr = sprom->core_pwr_info[0].maxpwr_2g;
4914                 pi->tx_srom_max_2g = txpwr;
4915
4916                 for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4917                         pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4918                         pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4919                 }
4920
4921                 cckpo = sprom->cck2gpo;
4922                 offset_ofdm = sprom->ofdm2gpo;
4923                 if (cckpo) {
4924                         uint max_pwr_chan = txpwr;
4925
4926                         for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4927                                 pi->tx_srom_max_rate_2g[i] =
4928                                         max_pwr_chan - ((cckpo & 0xf) * 2);
4929                                 cckpo >>= 4;
4930                         }
4931
4932                         for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4933                                 pi->tx_srom_max_rate_2g[i] =
4934                                         max_pwr_chan -
4935                                         ((offset_ofdm & 0xf) * 2);
4936                                 offset_ofdm >>= 4;
4937                         }
4938                 } else {
4939                         u8 opo = 0;
4940
4941                         opo = sprom->opo;
4942
4943                         for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
4944                                 pi->tx_srom_max_rate_2g[i] = txpwr;
4945
4946                         for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4947                                 pi->tx_srom_max_rate_2g[i] = txpwr -
4948                                                 ((offset_ofdm & 0xf) * 2);
4949                                 offset_ofdm >>= 4;
4950                         }
4951                         offset_mcs = sprom->mcs2gpo[1] << 16;
4952                         offset_mcs |= sprom->mcs2gpo[0];
4953                         pi_lcn->lcnphy_mcs20_po = offset_mcs;
4954                         for (i = TXP_FIRST_SISO_MCS_20;
4955                              i <= TXP_LAST_SISO_MCS_20; i++) {
4956                                 pi->tx_srom_max_rate_2g[i] =
4957                                         txpwr - ((offset_mcs & 0xf) * 2);
4958                                 offset_mcs >>= 4;
4959                         }
4960                 }
4961
4962                 pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
4963                 pi_lcn->lcnphy_measPower = sprom->measpower;
4964                 pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
4965                 pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
4966                 pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
4967                 pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
4968                 pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
4969                 pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
4970                 if (sprom->ant_available_bg > 1)
4971                         wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
4972                                 sprom->ant_available_bg);
4973         }
4974         pi_lcn->lcnphy_cck_dig_filt_type = -1;
4975
4976         return true;
4977 }
4978
4979 void wlc_2064_vco_cal(struct brcms_phy *pi)
4980 {
4981         u8 calnrst;
4982
4983         mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4984         calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4985         write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4986         udelay(1);
4987         write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4988         udelay(1);
4989         write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4990         udelay(300);
4991         mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4992 }
4993
4994 bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
4995 {
4996         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4997                 return false;
4998         else
4999                 return (LCNPHY_TX_PWR_CTRL_HW ==
5000                         wlc_lcnphy_get_tx_pwr_ctrl((pi)));
5001 }
5002
5003 void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
5004 {
5005         u16 pwr_ctrl;
5006         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5007                 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5008         } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
5009                 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
5010                 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
5011                 wlc_lcnphy_txpower_recalc_target(pi);
5012                 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5013         }
5014 }
5015
5016 void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
5017 {
5018         u8 channel = CHSPEC_CHANNEL(chanspec);
5019
5020         wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec);
5021
5022         wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
5023
5024         or_phy_reg(pi, 0x44a, 0x44);
5025         write_phy_reg(pi, 0x44a, 0x80);
5026
5027         wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
5028         udelay(1000);
5029
5030         wlc_lcnphy_toggle_afe_pwdn(pi);
5031
5032         write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
5033         write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
5034
5035         if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
5036                 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
5037
5038                 wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
5039         } else {
5040                 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
5041
5042                 wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
5043         }
5044
5045         if (pi->sh->boardflags & BFL_FEM)
5046                 wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
5047         else
5048                 wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
5049
5050         mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
5051         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
5052                 wlc_lcnphy_tssi_setup(pi);
5053 }
5054
5055 void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
5056 {
5057         kfree(pi->u.pi_lcnphy);
5058 }
5059
5060 bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
5061 {
5062         struct brcms_phy_lcnphy *pi_lcn;
5063
5064         pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
5065         if (pi->u.pi_lcnphy == NULL)
5066                 return false;
5067
5068         pi_lcn = pi->u.pi_lcnphy;
5069
5070         if (0 == (pi->sh->boardflags & BFL_NOPA)) {
5071                 pi->hwpwrctrl = true;
5072                 pi->hwpwrctrl_capable = true;
5073         }
5074
5075         pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc);
5076         pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5077
5078         pi->pi_fptr.init = wlc_phy_init_lcnphy;
5079         pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5080         pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5081         pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5082         pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5083         pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5084         pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5085         pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5086         pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5087
5088         if (!wlc_phy_txpwr_srom_read_lcnphy(pi)) {
5089                 kfree(pi->u.pi_lcnphy);
5090                 return false;
5091         }
5092
5093         if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5094                 if (pi_lcn->lcnphy_tempsense_option == 3) {
5095                         pi->hwpwrctrl = true;
5096                         pi->hwpwrctrl_capable = true;
5097                         pi->temppwrctrl_capable = false;
5098                 } else {
5099                         pi->hwpwrctrl = false;
5100                         pi->hwpwrctrl_capable = false;
5101                         pi->temppwrctrl_capable = true;
5102                 }
5103         }
5104
5105         return true;
5106 }
5107
5108 static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
5109 {
5110         u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5111
5112         trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5113         ext_lna = (u16) (gain >> 29) & 0x01;
5114         lna1 = (u16) (gain >> 0) & 0x0f;
5115         lna2 = (u16) (gain >> 4) & 0x0f;
5116         tia = (u16) (gain >> 8) & 0xf;
5117         biq0 = (u16) (gain >> 12) & 0xf;
5118         biq1 = (u16) (gain >> 16) & 0xf;
5119
5120         gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5121                           ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5122                           ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5123         gain16_19 = biq1;
5124
5125         mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5126         mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5127         mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5128         mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5129         mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5130
5131         if (CHSPEC_IS2G(pi->radio_chanspec)) {
5132                 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5133                 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5134         }
5135         wlc_lcnphy_rx_gain_override_enable(pi, true);
5136 }
5137
5138 static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
5139 {
5140         u32 received_power = 0;
5141         s32 max_index = 0;
5142         u32 gain_code = 0;
5143         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5144
5145         max_index = 36;
5146         if (*gain_index >= 0)
5147                 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5148
5149         if (-1 == *gain_index) {
5150                 *gain_index = 0;
5151                 while ((*gain_index <= (s32) max_index)
5152                        && (received_power < 700)) {
5153                         wlc_lcnphy_set_rx_gain(pi,
5154                                                lcnphy_23bitgaincode_table
5155                                                [*gain_index]);
5156                         received_power =
5157                                 wlc_lcnphy_measure_digital_power(
5158                                         pi,
5159                                         pi_lcn->
5160                                         lcnphy_noise_samples);
5161                         (*gain_index)++;
5162                 }
5163                 (*gain_index)--;
5164         } else {
5165                 wlc_lcnphy_set_rx_gain(pi, gain_code);
5166                 received_power =
5167                         wlc_lcnphy_measure_digital_power(pi,
5168                                                          pi_lcn->
5169                                                          lcnphy_noise_samples);
5170         }
5171
5172         return received_power;
5173 }
5174
5175 s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
5176 {
5177         s32 gain = 0;
5178         s32 nominal_power_db;
5179         s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5180             input_power_db;
5181         s32 received_power, temperature;
5182         u32 power;
5183         u32 msb1, msb2, val1, val2, diff1, diff2;
5184         uint freq;
5185         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5186
5187         received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5188
5189         gain = lcnphy_gain_table[gain_index];
5190
5191         nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5192
5193         power = (received_power * 16);
5194         msb1 = ffs(power) - 1;
5195         msb2 = msb1 + 1;
5196         val1 = 1 << msb1;
5197         val2 = 1 << msb2;
5198         diff1 = (power - val1);
5199         diff2 = (val2 - power);
5200         if (diff1 < diff2)
5201                 log_val = msb1;
5202         else
5203                 log_val = msb2;
5204
5205         log_val = log_val * 3;
5206
5207         gain_mismatch = (nominal_power_db / 2) - (log_val);
5208
5209         desired_gain = gain + gain_mismatch;
5210
5211         input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5212
5213         if (input_power_offset_db > 127)
5214                 input_power_offset_db -= 256;
5215
5216         input_power_db = input_power_offset_db - desired_gain;
5217
5218         input_power_db =
5219                 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5220
5221         freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5222         if ((freq > 2427) && (freq <= 2467))
5223                 input_power_db = input_power_db - 1;
5224
5225         temperature = pi_lcn->lcnphy_lastsensed_temperature;
5226
5227         if ((temperature - 15) < -30)
5228                 input_power_db =
5229                         input_power_db +
5230                         (((temperature - 10 - 25) * 286) >> 12) -
5231                         7;
5232         else if ((temperature - 15) < 4)
5233                 input_power_db =
5234                         input_power_db +
5235                         (((temperature - 10 - 25) * 286) >> 12) -
5236                         3;
5237         else
5238                 input_power_db = input_power_db +
5239                                         (((temperature - 10 - 25) * 286) >> 12);
5240
5241         wlc_lcnphy_rx_gain_override_enable(pi, 0);
5242
5243         return input_power_db;
5244 }