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