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