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