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