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