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