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