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