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