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