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