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