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