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
152struct lcnphy_txgains {
153	u16 gm_gain;
154	u16 pga_gain;
155	u16 pad_gain;
156	u16 dac_gain;
157};
158
159enum 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
167struct lcnphy_rx_iqcomp {
168	u8 chan;
169	s16 a;
170	s16 b;
171};
172
173struct lcnphy_spb_tone {
174	s16 re;
175	s16 im;
176};
177
178struct lcnphy_unsign16_struct {
179	u16 re;
180	u16 im;
181};
182
183struct lcnphy_iq_est {
184	u32 iq_prod;
185	u32 i_pwr;
186	u32 q_pwr;
187};
188
189struct lcnphy_sfo_cfg {
190	u16 ptcentreTs20;
191	u16 ptcentreFactor;
192};
193
194enum lcnphy_papd_cal_type {
195	LCNPHY_PAPD_CAL_CW,
196	LCNPHY_PAPD_CAL_OFDM
197};
198
199typedef u16 iqcal_gain_params_lcnphy[9];
200
201static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
202	{0, 0, 0, 0, 0, 0, 0, 0, 0},
203};
204
205static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
206	tbl_iqcal_gainparams_lcnphy_2G,
207};
208
209static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
210	ARRAY_SIZE(tbl_iqcal_gainparams_lcnphy_2G),
211};
212
213static 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
230static const
231u16 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
254static const
255u16 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
278static const
279struct 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
314static const
315u16 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
338static const
339u16 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
356static const
357u16 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
371static const
372struct 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
426static 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
466static 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
506static 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
547struct 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
560static 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
577static 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
889static 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
920static 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
976void 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
981void 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
986static void
987wlc_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
1000static void
1001wlc_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
1015static u32
1016wlc_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
1041static 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
1061static void
1062wlc_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
1078static 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
1089static 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
1100static void
1101wlc_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
1126static void
1127wlc_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
1163static 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
1173static 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
1179static 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
1195static bool
1196wlc_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
1234cleanup:
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
1242static 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);
1309cleanup:
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
1323static 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
1332static 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
1369static bool
1370wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
1371		     const struct lcnphy_rx_iqcomp *iqcomp,
1372		     int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
1373		     int tx_gain_idx)
1374{
1375	struct lcnphy_txgains old_gains;
1376	u16 tx_pwr_ctrl;
1377	u8 tx_gain_index_old = 0;
1378	bool result = false, tx_gain_override_old = false;
1379	u16 i, Core1TxControl_old, RFOverride0_old,
1380	    RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
1381	    rfoverride3_old, rfoverride3val_old, rfoverride4_old,
1382	    rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
1383	int tia_gain, lna2_gain, biq1_gain;
1384	bool set_gain;
1385	u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
1386	u16 values_to_save[11];
1387	s16 *ptr;
1388	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1389
1390	ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
1391	if (NULL == ptr)
1392		return false;
1393	if (module == 2) {
1394		while (iqcomp_sz--) {
1395			if (iqcomp[iqcomp_sz].chan ==
1396			    CHSPEC_CHANNEL(pi->radio_chanspec)) {
1397				wlc_lcnphy_set_rx_iq_comp(pi,
1398							  (u16)
1399							  iqcomp[iqcomp_sz].a,
1400							  (u16)
1401							  iqcomp[iqcomp_sz].b);
1402				result = true;
1403				break;
1404			}
1405		}
1406		goto cal_done;
1407	}
1408
1409	WARN_ON(module != 1);
1410	tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1411	wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1412
1413	for (i = 0; i < 11; i++)
1414		values_to_save[i] =
1415			read_radio_reg(pi, rxiq_cal_rf_reg[i]);
1416	Core1TxControl_old = read_phy_reg(pi, 0x631);
1417
1418	or_phy_reg(pi, 0x631, 0x0015);
1419
1420	RFOverride0_old = read_phy_reg(pi, 0x44c);
1421	RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
1422	rfoverride2_old = read_phy_reg(pi, 0x4b0);
1423	rfoverride2val_old = read_phy_reg(pi, 0x4b1);
1424	rfoverride3_old = read_phy_reg(pi, 0x4f9);
1425	rfoverride3val_old = read_phy_reg(pi, 0x4fa);
1426	rfoverride4_old = read_phy_reg(pi, 0x938);
1427	rfoverride4val_old = read_phy_reg(pi, 0x939);
1428	afectrlovr_old = read_phy_reg(pi, 0x43b);
1429	afectrlovrval_old = read_phy_reg(pi, 0x43c);
1430	old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1431	old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1432
1433	tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1434	if (tx_gain_override_old) {
1435		wlc_lcnphy_get_tx_gain(pi, &old_gains);
1436		tx_gain_index_old = pi_lcn->lcnphy_current_index;
1437	}
1438
1439	wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
1440
1441	mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
1442	mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
1443
1444	mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
1445	mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
1446
1447	write_radio_reg(pi, RADIO_2064_REG116, 0x06);
1448	write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
1449	write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
1450	write_radio_reg(pi, RADIO_2064_REG098, 0x03);
1451	write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
1452	mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
1453	write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
1454	write_radio_reg(pi, RADIO_2064_REG114, 0x01);
1455	write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
1456	write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
1457
1458	mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
1459	mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
1460	mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
1461	mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
1462	mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
1463	mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
1464	mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
1465	mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
1466	mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
1467	mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
1468
1469	mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
1470	mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
1471
1472	write_phy_reg(pi, 0x6da, 0xffff);
1473	or_phy_reg(pi, 0x6db, 0x3);
1474
1475	wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
1476	for (lna2_gain = 3; lna2_gain >= 0; lna2_gain--) {
1477		for (tia_gain = 4; tia_gain >= 0; tia_gain--) {
1478			for (biq1_gain = 6; biq1_gain >= 0; biq1_gain--) {
1479				set_gain = wlc_lcnphy_rx_iq_cal_gain(pi,
1480								     (u16)
1481								     biq1_gain,
1482								     (u16)
1483								     tia_gain,
1484								     (u16)
1485								     lna2_gain);
1486				if (!set_gain)
1487					continue;
1488
1489				result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024);
1490				goto stop_tone;
1491			}
1492		}
1493	}
1494
1495stop_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
1529cal_done:
1530	kfree(ptr);
1531	return result;
1532}
1533
1534s8 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
1549void 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
1580static 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
1597static void
1598wlc_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
1617static void
1618wlc_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
1673static void
1674wlc_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
1844static int
1845wlc_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
1921static 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
1932static 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
1962static 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
1977static 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
1990static 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
2013enum lcnphy_tssi_mode {
2014	LCNPHY_TSSI_PRE_PA,
2015	LCNPHY_TSSI_POST_PA,
2016	LCNPHY_TSSI_EXT
2017};
2018
2019static void
2020wlc_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
2069static 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
2090static 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
2135static 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
2262void 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
2281s32 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
2292static 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
2302void 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
2333static 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
2386static 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
2446static 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
2459void 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
2512static void
2513wlc_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
2604static 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
2619static void
2620wlc_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
2633static void
2634wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
2635		       struct lcnphy_txgains *target_gains,
2636		       enum lcnphy_cal_mode cal_mode, bool keep_tone)
2637{
2638
2639	struct lcnphy_txgains cal_gains, temp_gains;
2640	u16 hash;
2641	u8 band_idx;
2642	int j;
2643	u16 ncorr_override[5];
2644	u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
2645			      0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
2646
2647	u16 commands_fullcal[] = {
2648		0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2649	};
2650
2651	u16 commands_recal[] = {
2652		0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2653	};
2654
2655	u16 command_nums_fullcal[] = {
2656		0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2657	};
2658
2659	u16 command_nums_recal[] = {
2660		0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2661	};
2662	u16 *command_nums = command_nums_fullcal;
2663
2664	u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
2665	u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
2666	u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
2667	bool tx_gain_override_old;
2668	struct lcnphy_txgains old_gains;
2669	uint i, n_cal_cmds = 0, n_cal_start = 0;
2670	u16 *values_to_save;
2671	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2672
2673	values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
2674	if (NULL == values_to_save)
2675		return;
2676
2677	save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
2678	save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
2679
2680	or_phy_reg(pi, 0x6da, 0x40);
2681	or_phy_reg(pi, 0x6db, 0x3);
2682
2683	switch (cal_mode) {
2684	case LCNPHY_CAL_FULL:
2685		start_coeffs = syst_coeffs;
2686		cal_cmds = commands_fullcal;
2687		n_cal_cmds = ARRAY_SIZE(commands_fullcal);
2688		break;
2689
2690	case LCNPHY_CAL_RECAL:
2691		start_coeffs = syst_coeffs;
2692		cal_cmds = commands_recal;
2693		n_cal_cmds = ARRAY_SIZE(commands_recal);
2694		command_nums = command_nums_recal;
2695		break;
2696
2697	default:
2698		break;
2699	}
2700
2701	wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2702				      start_coeffs, 11, 16, 64);
2703
2704	write_phy_reg(pi, 0x6da, 0xffff);
2705	mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
2706
2707	tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2708
2709	mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2710
2711	wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2712
2713	save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
2714
2715	mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
2716
2717	mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
2718
2719	wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
2720
2721	tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2722	if (tx_gain_override_old)
2723		wlc_lcnphy_get_tx_gain(pi, &old_gains);
2724
2725	if (!target_gains) {
2726		if (!tx_gain_override_old)
2727			wlc_lcnphy_set_tx_pwr_by_index(pi,
2728						       pi_lcn->lcnphy_tssi_idx);
2729		wlc_lcnphy_get_tx_gain(pi, &temp_gains);
2730		target_gains = &temp_gains;
2731	}
2732
2733	hash = (target_gains->gm_gain << 8) |
2734	       (target_gains->pga_gain << 4) | (target_gains->pad_gain);
2735
2736	band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
2737
2738	cal_gains = *target_gains;
2739	memset(ncorr_override, 0, sizeof(ncorr_override));
2740	for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
2741		if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
2742			cal_gains.gm_gain =
2743				tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
2744			cal_gains.pga_gain =
2745				tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
2746			cal_gains.pad_gain =
2747				tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
2748			memcpy(ncorr_override,
2749			       &tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
2750			       sizeof(ncorr_override));
2751			break;
2752		}
2753	}
2754
2755	wlc_lcnphy_set_tx_gain(pi, &cal_gains);
2756
2757	write_phy_reg(pi, 0x453, 0xaa9);
2758	write_phy_reg(pi, 0x93d, 0xc0);
2759
2760	wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2761				      lcnphy_iqcal_loft_gainladder,
2762				      ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
2763				      16, 0);
2764
2765	wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2766				      lcnphy_iqcal_ir_gainladder,
2767				      ARRAY_SIZE(
2768					      lcnphy_iqcal_ir_gainladder), 16,
2769				      32);
2770
2771	if (pi->phy_tx_tone_freq) {
2772
2773		wlc_lcnphy_stop_tx_tone(pi);
2774		udelay(5);
2775		wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2776	} else {
2777		wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2778	}
2779
2780	write_phy_reg(pi, 0x6da, 0xffff);
2781
2782	for (i = n_cal_start; i < n_cal_cmds; i++) {
2783		u16 zero_diq = 0;
2784		u16 best_coeffs[11];
2785		u16 command_num;
2786
2787		cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2788
2789		command_num = command_nums[i];
2790		if (ncorr_override[cal_type])
2791			command_num =
2792				ncorr_override[cal_type] << 8 | (command_num &
2793								 0xff);
2794
2795		write_phy_reg(pi, 0x452, command_num);
2796
2797		if ((cal_type == 3) || (cal_type == 4)) {
2798			wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2799						     &diq_start, 1, 16, 69);
2800
2801			wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2802						      &zero_diq, 1, 16, 69);
2803		}
2804
2805		write_phy_reg(pi, 0x451, cal_cmds[i]);
2806
2807		if (!wlc_lcnphy_iqcal_wait(pi))
2808			goto cleanup;
2809
2810		wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2811					     best_coeffs,
2812					     ARRAY_SIZE(best_coeffs), 16, 96);
2813		wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2814					      best_coeffs,
2815					      ARRAY_SIZE(best_coeffs), 16, 64);
2816
2817		if ((cal_type == 3) || (cal_type == 4))
2818			wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2819						      &diq_start, 1, 16, 69);
2820		wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2821					     pi_lcn->lcnphy_cal_results.
2822					     txiqlocal_bestcoeffs,
2823					     ARRAY_SIZE(pi_lcn->
2824							lcnphy_cal_results.
2825							txiqlocal_bestcoeffs),
2826					     16, 96);
2827	}
2828
2829	wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2830				     pi_lcn->lcnphy_cal_results.
2831				     txiqlocal_bestcoeffs,
2832				     ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
2833						txiqlocal_bestcoeffs), 16, 96);
2834	pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
2835
2836	wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2837				      &pi_lcn->lcnphy_cal_results.
2838				      txiqlocal_bestcoeffs[0], 4, 16, 80);
2839
2840	wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2841				      &pi_lcn->lcnphy_cal_results.
2842				      txiqlocal_bestcoeffs[5], 2, 16, 85);
2843
2844cleanup:
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
2864static 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
2937static 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
3079static 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
3155static 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
3165void
3166wlc_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
3175void 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
3191void 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
3203void 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
3262static 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
3281void 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
3358static void
3359wlc_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
3385void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)
3386{
3387
3388	u8 phybw40;
3389	phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3390
3391	if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
3392		mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3393		mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3394	} else {
3395		mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3396		mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3397	}
3398
3399	if (phybw40 == 0) {
3400		mod_phy_reg((pi), 0x410,
3401			    (0x1 << 6) |
3402			    (0x1 << 5),
3403			    ((CHSPEC_IS2G(
3404				      pi->radio_chanspec)) ? (!mode) : 0) <<
3405			    6 | (!mode) << 5);
3406		mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
3407	}
3408}
3409
3410void
3411wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
3412			 bool iqcalmode)
3413{
3414	u8 phy_bw;
3415	u16 num_samps, t, k;
3416	u32 bw;
3417	s32 theta = 0, rot = 0;
3418	struct cordic_iq tone_samp;
3419	u32 data_buf[64];
3420	u16 i_samp, q_samp;
3421	struct phytbl_info tab;
3422	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3423
3424	pi->phy_tx_tone_freq = f_kHz;
3425
3426	wlc_lcnphy_deaf_mode(pi, true);
3427
3428	phy_bw = 40;
3429	if (pi_lcn->lcnphy_spurmod) {
3430		write_phy_reg(pi, 0x942, 0x2);
3431		write_phy_reg(pi, 0x93b, 0x0);
3432		write_phy_reg(pi, 0x93c, 0x0);
3433		wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3434	}
3435
3436	if (f_kHz) {
3437		k = 1;
3438		do {
3439			bw = phy_bw * 1000 * k;
3440			num_samps = bw / abs(f_kHz);
3441			k++;
3442		} while ((num_samps * (u32) (abs(f_kHz))) != bw);
3443	} else
3444		num_samps = 2;
3445
3446	rot = ((f_kHz * 36) / phy_bw) / 100;
3447	theta = 0;
3448
3449	for (t = 0; t < num_samps; t++) {
3450
3451		tone_samp = cordic_calc_iq(theta);
3452
3453		theta += rot;
3454
3455		i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
3456		q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
3457		data_buf[t] = (i_samp << 10) | q_samp;
3458	}
3459
3460	mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
3461
3462	mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
3463
3464	tab.tbl_ptr = data_buf;
3465	tab.tbl_len = num_samps;
3466	tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
3467	tab.tbl_offset = 0;
3468	tab.tbl_width = 32;
3469	wlc_lcnphy_write_table(pi, &tab);
3470
3471	wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
3472}
3473
3474void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
3475{
3476	s16 playback_status;
3477	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3478
3479	pi->phy_tx_tone_freq = 0;
3480	if (pi_lcn->lcnphy_spurmod) {
3481		write_phy_reg(pi, 0x942, 0x7);
3482		write_phy_reg(pi, 0x93b, 0x2017);
3483		write_phy_reg(pi, 0x93c, 0x27c5);
3484		wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3485	}
3486
3487	playback_status = read_phy_reg(pi, 0x644);
3488	if (playback_status & (0x1 << 0)) {
3489		wlc_lcnphy_tx_pu(pi, 0);
3490		mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
3491	} else if (playback_status & (0x1 << 1))
3492		mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
3493
3494	mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
3495
3496	mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
3497
3498	mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
3499
3500	and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
3501
3502	wlc_lcnphy_deaf_mode(pi, false);
3503}
3504
3505static void
3506wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3507{
3508	u16 di0dq0;
3509	u16 x, y, data_rf;
3510	int k;
3511	switch (cal_type) {
3512	case 0:
3513		wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3514		break;
3515	case 2:
3516		di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3517		wlc_lcnphy_set_tx_locc(pi, di0dq0);
3518		break;
3519	case 3:
3520		k = wlc_lcnphy_calc_floor(coeff_x, 0);
3521		y = 8 + k;
3522		k = wlc_lcnphy_calc_floor(coeff_x, 1);
3523		x = 8 - k;
3524		data_rf = (x * 16 + y);
3525		write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3526		k = wlc_lcnphy_calc_floor(coeff_y, 0);
3527		y = 8 + k;
3528		k = wlc_lcnphy_calc_floor(coeff_y, 1);
3529		x = 8 - k;
3530		data_rf = (x * 16 + y);
3531		write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3532		break;
3533	case 4:
3534		k = wlc_lcnphy_calc_floor(coeff_x, 0);
3535		y = 8 + k;
3536		k = wlc_lcnphy_calc_floor(coeff_x, 1);
3537		x = 8 - k;
3538		data_rf = (x * 16 + y);
3539		write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3540		k = wlc_lcnphy_calc_floor(coeff_y, 0);
3541		y = 8 + k;
3542		k = wlc_lcnphy_calc_floor(coeff_y, 1);
3543		x = 8 - k;
3544		data_rf = (x * 16 + y);
3545		write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3546		break;
3547	}
3548}
3549
3550static struct lcnphy_unsign16_struct
3551wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
3552{
3553	u16 a, b, didq;
3554	u8 di0, dq0, ei, eq, fi, fq;
3555	struct lcnphy_unsign16_struct cc;
3556	cc.re = 0;
3557	cc.im = 0;
3558	switch (cal_type) {
3559	case 0:
3560		wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3561		cc.re = a;
3562		cc.im = b;
3563		break;
3564	case 2:
3565		didq = wlc_lcnphy_get_tx_locc(pi);
3566		di0 = (((didq & 0xff00) << 16) >> 24);
3567		dq0 = (((didq & 0x00ff) << 24) >> 24);
3568		cc.re = (u16) di0;
3569		cc.im = (u16) dq0;
3570		break;
3571	case 3:
3572		wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3573		cc.re = (u16) ei;
3574		cc.im = (u16) eq;
3575		break;
3576	case 4:
3577		wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3578		cc.re = (u16) fi;
3579		cc.im = (u16) fq;
3580		break;
3581	}
3582	return cc;
3583}
3584
3585static void
3586wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
3587		    s16 *ptr, int mode)
3588{
3589	u32 curval1, curval2, stpptr, curptr, strptr, val;
3590	u16 sslpnCalibClkEnCtrl, timer;
3591	u16 old_sslpnCalibClkEnCtrl;
3592	s16 imag, real;
3593	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3594
3595	timer = 0;
3596	old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3597
3598	curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));
3599	ptr[130] = 0;
3600	bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),
3601		     ((1 << 6) | curval1));
3602
3603	bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);
3604	bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);
3605	udelay(20);
3606	curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));
3607	bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),
3608		     curval2 | 0x30);
3609
3610	write_phy_reg(pi, 0x555, 0x0);
3611	write_phy_reg(pi, 0x5a6, 0x5);
3612
3613	write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3614	write_phy_reg(pi, 0x5cf, 3);
3615	write_phy_reg(pi, 0x5a5, 0x3);
3616	write_phy_reg(pi, 0x583, 0x0);
3617	write_phy_reg(pi, 0x584, 0x0);
3618	write_phy_reg(pi, 0x585, 0x0fff);
3619	write_phy_reg(pi, 0x586, 0x0000);
3620
3621	write_phy_reg(pi, 0x580, 0x4501);
3622
3623	sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3624	write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3625	stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));
3626	curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3627	do {
3628		udelay(10);
3629		curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3630		timer++;
3631	} while ((curptr != stpptr) && (timer < 500));
3632
3633	bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);
3634	strptr = 0x7E00;
3635	bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);
3636	while (strptr < 0x8000) {
3637		val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));
3638		imag = ((val >> 16) & 0x3ff);
3639		real = ((val) & 0x3ff);
3640		if (imag > 511)
3641			imag -= 1024;
3642
3643		if (real > 511)
3644			real -= 1024;
3645
3646		if (pi_lcn->lcnphy_iqcal_swp_dis)
3647			ptr[(strptr - 0x7E00) / 4] = real;
3648		else
3649			ptr[(strptr - 0x7E00) / 4] = imag;
3650
3651		if (clip_detect_algo) {
3652			if (imag > thresh || imag < -thresh) {
3653				strptr = 0x8000;
3654				ptr[130] = 1;
3655			}
3656		}
3657
3658		strptr += 4;
3659	}
3660
3661	write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3662	bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);
3663	bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);
3664}
3665
3666static void
3667wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
3668	      int step_size_lg2)
3669{
3670	const struct lcnphy_spb_tone *phy_c1;
3671	struct lcnphy_spb_tone phy_c2;
3672	struct lcnphy_unsign16_struct phy_c3;
3673	int phy_c4, phy_c5, k, l, j, phy_c6;
3674	u16 phy_c7, phy_c8, phy_c9;
3675	s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
3676	s16 *ptr, phy_c17;
3677	s32 phy_c18, phy_c19;
3678	u32 phy_c20, phy_c21;
3679	bool phy_c22, phy_c23, phy_c24, phy_c25;
3680	u16 phy_c26, phy_c27;
3681	u16 phy_c28, phy_c29, phy_c30;
3682	u16 phy_c31;
3683	u16 *phy_c32;
3684	phy_c21 = 0;
3685	phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
3686	ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
3687	if (NULL == ptr)
3688		return;
3689
3690	phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
3691	if (NULL == phy_c32) {
3692		kfree(ptr);
3693		return;
3694	}
3695	phy_c26 = read_phy_reg(pi, 0x6da);
3696	phy_c27 = read_phy_reg(pi, 0x6db);
3697	phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
3698	write_phy_reg(pi, 0x93d, 0xC0);
3699
3700	wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
3701	write_phy_reg(pi, 0x6da, 0xffff);
3702	or_phy_reg(pi, 0x6db, 0x3);
3703
3704	wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
3705	udelay(500);
3706	phy_c28 = read_phy_reg(pi, 0x938);
3707	phy_c29 = read_phy_reg(pi, 0x4d7);
3708	phy_c30 = read_phy_reg(pi, 0x4d8);
3709	or_phy_reg(pi, 0x938, 0x1 << 2);
3710	or_phy_reg(pi, 0x4d7, 0x1 << 2);
3711	or_phy_reg(pi, 0x4d7, 0x1 << 3);
3712	mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
3713	or_phy_reg(pi, 0x4d8, 1 << 0);
3714	or_phy_reg(pi, 0x4d8, 1 << 1);
3715	mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
3716	mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
3717	phy_c1 = &lcnphy_spb_tone_3750[0];
3718	phy_c4 = 32;
3719
3720	if (num_levels == 0) {
3721		if (cal_type != 0)
3722			num_levels = 4;
3723		else
3724			num_levels = 9;
3725	}
3726	if (step_size_lg2 == 0) {
3727		if (cal_type != 0)
3728			step_size_lg2 = 3;
3729		else
3730			step_size_lg2 = 8;
3731	}
3732
3733	phy_c7 = (1 << step_size_lg2);
3734	phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
3735	phy_c15 = (s16) phy_c3.re;
3736	phy_c16 = (s16) phy_c3.im;
3737	if (cal_type == 2) {
3738		if (phy_c3.re > 127)
3739			phy_c15 = phy_c3.re - 256;
3740		if (phy_c3.im > 127)
3741			phy_c16 = phy_c3.im - 256;
3742	}
3743	wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3744	udelay(20);
3745	for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
3746		phy_c23 = true;
3747		phy_c22 = false;
3748		switch (cal_type) {
3749		case 0:
3750			phy_c10 = 511;
3751			break;
3752		case 2:
3753			phy_c10 = 127;
3754			break;
3755		case 3:
3756			phy_c10 = 15;
3757			break;
3758		case 4:
3759			phy_c10 = 15;
3760			break;
3761		}
3762
3763		phy_c9 = read_phy_reg(pi, 0x93d);
3764		phy_c9 = 2 * phy_c9;
3765		phy_c24 = false;
3766		phy_c5 = 7;
3767		phy_c25 = true;
3768		while (1) {
3769			write_radio_reg(pi, RADIO_2064_REG026,
3770					(phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
3771			udelay(50);
3772			phy_c22 = false;
3773			ptr[130] = 0;
3774			wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
3775			if (ptr[130] == 1)
3776				phy_c22 = true;
3777			if (phy_c22)
3778				phy_c5 -= 1;
3779			if ((phy_c22 != phy_c24) && (!phy_c25))
3780				break;
3781			if (!phy_c22)
3782				phy_c5 += 1;
3783			if (phy_c5 <= 0 || phy_c5 >= 7)
3784				break;
3785			phy_c24 = phy_c22;
3786			phy_c25 = false;
3787		}
3788
3789		if (phy_c5 < 0)
3790			phy_c5 = 0;
3791		else if (phy_c5 > 7)
3792			phy_c5 = 7;
3793
3794		for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
3795			for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
3796				phy_c11 = phy_c15 + k;
3797				phy_c12 = phy_c16 + l;
3798
3799				if (phy_c11 < -phy_c10)
3800					phy_c11 = -phy_c10;
3801				else if (phy_c11 > phy_c10)
3802					phy_c11 = phy_c10;
3803				if (phy_c12 < -phy_c10)
3804					phy_c12 = -phy_c10;
3805				else if (phy_c12 > phy_c10)
3806					phy_c12 = phy_c10;
3807				wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
3808						  phy_c12);
3809				udelay(20);
3810				wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
3811
3812				phy_c18 = 0;
3813				phy_c19 = 0;
3814				for (j = 0; j < 128; j++) {
3815					if (cal_type != 0)
3816						phy_c6 = j % phy_c4;
3817					else
3818						phy_c6 = (2 * j) % phy_c4;
3819
3820					phy_c2.re = phy_c1[phy_c6].re;
3821					phy_c2.im = phy_c1[phy_c6].im;
3822					phy_c17 = ptr[j];
3823					phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
3824					phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
3825				}
3826
3827				phy_c18 = phy_c18 >> 10;
3828				phy_c19 = phy_c19 >> 10;
3829				phy_c20 = ((phy_c18 * phy_c18) +
3830					   (phy_c19 * phy_c19));
3831
3832				if (phy_c23 || phy_c20 < phy_c21) {
3833					phy_c21 = phy_c20;
3834					phy_c13 = phy_c11;
3835					phy_c14 = phy_c12;
3836				}
3837				phy_c23 = false;
3838			}
3839		}
3840		phy_c23 = true;
3841		phy_c15 = phy_c13;
3842		phy_c16 = phy_c14;
3843		phy_c7 = phy_c7 >> 1;
3844		wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3845		udelay(20);
3846	}
3847	goto cleanup;
3848cleanup:
3849	wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
3850	wlc_lcnphy_stop_tx_tone(pi);
3851	write_phy_reg(pi, 0x6da, phy_c26);
3852	write_phy_reg(pi, 0x6db, phy_c27);
3853	write_phy_reg(pi, 0x938, phy_c28);
3854	write_phy_reg(pi, 0x4d7, phy_c29);
3855	write_phy_reg(pi, 0x4d8, phy_c30);
3856	write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
3857
3858	kfree(phy_c32);
3859	kfree(ptr);
3860}
3861
3862void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
3863{
3864	u16 iqcc[2];
3865	struct phytbl_info tab;
3866
3867	tab.tbl_ptr = iqcc;
3868	tab.tbl_len = 2;
3869	tab.tbl_id = 0;
3870	tab.tbl_offset = 80;
3871	tab.tbl_width = 16;
3872	wlc_lcnphy_read_table(pi, &tab);
3873
3874	*a = iqcc[0];
3875	*b = iqcc[1];
3876}
3877
3878static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
3879{
3880	struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3881
3882	wlc_lcnphy_set_cc(pi, 0, 0, 0);
3883	wlc_lcnphy_set_cc(pi, 2, 0, 0);
3884	wlc_lcnphy_set_cc(pi, 3, 0, 0);
3885	wlc_lcnphy_set_cc(pi, 4, 0, 0);
3886
3887	wlc_lcnphy_a1(pi, 4, 0, 0);
3888	wlc_lcnphy_a1(pi, 3, 0, 0);
3889	wlc_lcnphy_a1(pi, 2, 3, 2);
3890	wlc_lcnphy_a1(pi, 0, 5, 8);
3891	wlc_lcnphy_a1(pi, 2, 2, 1);
3892	wlc_lcnphy_a1(pi, 0, 4, 3);
3893
3894	iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3895	locc2 = wlc_lcnphy_get_cc(pi, 2);
3896	locc3 = wlc_lcnphy_get_cc(pi, 3);
3897	locc4 = wlc_lcnphy_get_cc(pi, 4);
3898}
3899
3900u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
3901{
3902	struct phytbl_info tab;
3903	u16 didq;
3904
3905	tab.tbl_id = 0;
3906	tab.tbl_width = 16;
3907	tab.tbl_ptr = &didq;
3908	tab.tbl_len = 1;
3909	tab.tbl_offset = 85;
3910	wlc_lcnphy_read_table(pi, &tab);
3911
3912	return didq;
3913}
3914
3915static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
3916{
3917
3918	struct lcnphy_txgains target_gains, old_gains;
3919	u8 save_bb_mult;
3920	u16 a, b, didq, save_pa_gain = 0;
3921	uint idx, SAVE_txpwrindex = 0xFF;
3922	u32 val;
3923	u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3924	struct phytbl_info tab;
3925	u8 ei0, eq0, fi0, fq0;
3926	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3927
3928	wlc_lcnphy_get_tx_gain(pi, &old_gains);
3929	save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
3930
3931	save_bb_mult = wlc_lcnphy_get_bbmult(pi);
3932
3933	if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
3934		SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
3935
3936	wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3937
3938	target_gains.gm_gain = 7;
3939	target_gains.pga_gain = 0;
3940	target_gains.pad_gain = 21;
3941	target_gains.dac_gain = 0;
3942	wlc_lcnphy_set_tx_gain(pi, &target_gains);
3943
3944	if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
3945
3946		wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
3947
3948		wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3949				       (pi_lcn->
3950					lcnphy_recal ? LCNPHY_CAL_RECAL :
3951					LCNPHY_CAL_FULL), false);
3952	} else {
3953		wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3954		wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3955	}
3956
3957	wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
3958	if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
3959		if (CHSPEC_IS5G(pi->radio_chanspec)) {
3960			target_gains.gm_gain = 255;
3961			target_gains.pga_gain = 255;
3962			target_gains.pad_gain = 0xf0;
3963			target_gains.dac_gain = 0;
3964		} else {
3965			target_gains.gm_gain = 7;
3966			target_gains.pga_gain = 45;
3967			target_gains.pad_gain = 186;
3968			target_gains.dac_gain = 0;
3969		}
3970
3971		if (LCNREV_IS(pi->pubpi.phy_rev, 1)
3972		    || pi_lcn->lcnphy_hw_iqcal_en) {
3973
3974			target_gains.pga_gain = 0;
3975			target_gains.pad_gain = 30;
3976			wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3977			wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3978					       LCNPHY_CAL_FULL, false);
3979		} else {
3980			wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3981		}
3982	}
3983
3984	wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3985
3986	didq = wlc_lcnphy_get_tx_locc(pi);
3987
3988	tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3989	tab.tbl_width = 32;
3990	tab.tbl_ptr = &val;
3991
3992	tab.tbl_len = 1;
3993	tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
3994
3995	for (idx = 0; idx < 128; idx++) {
3996		tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
3997
3998		wlc_lcnphy_read_table(pi, &tab);
3999		val = (val & 0xfff00000) |
4000		      ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
4001		wlc_lcnphy_write_table(pi, &tab);
4002
4003		val = didq;
4004		tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
4005		wlc_lcnphy_write_table(pi, &tab);
4006	}
4007
4008	pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
4009	pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
4010	pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
4011	pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
4012	pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
4013	pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
4014	pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
4015
4016	wlc_lcnphy_set_bbmult(pi, save_bb_mult);
4017	wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
4018	wlc_lcnphy_set_tx_gain(pi, &old_gains);
4019
4020	if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
4021		wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4022	else
4023		wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
4024}
4025
4026s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
4027{
4028	u16 tempsenseval1, tempsenseval2;
4029	s16 avg = 0;
4030	bool suspend = false;
4031
4032	if (mode == 1) {
4033		suspend = (0 == (bcma_read32(pi->d11core,
4034					     D11REGOFFS(maccontrol)) &
4035				 MCTL_EN_MAC));
4036		if (!suspend)
4037			wlapi_suspend_mac_and_wait(pi->sh->physhim);
4038		wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4039	}
4040	tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4041	tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4042
4043	if (tempsenseval1 > 255)
4044		avg = (s16) (tempsenseval1 - 512);
4045	else
4046		avg = (s16) tempsenseval1;
4047
4048	if (tempsenseval2 > 255)
4049		avg += (s16) (tempsenseval2 - 512);
4050	else
4051		avg += (s16) tempsenseval2;
4052
4053	avg /= 2;
4054
4055	if (mode == 1) {
4056
4057		mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4058
4059		udelay(100);
4060		mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4061
4062		if (!suspend)
4063			wlapi_enable_mac(pi->sh->physhim);
4064	}
4065	return avg;
4066}
4067
4068u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
4069{
4070	u16 tempsenseval1, tempsenseval2;
4071	s32 avg = 0;
4072	bool suspend = false;
4073	u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4074	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4075
4076	if (mode == 1) {
4077		suspend = (0 == (bcma_read32(pi->d11core,
4078					     D11REGOFFS(maccontrol)) &
4079				 MCTL_EN_MAC));
4080		if (!suspend)
4081			wlapi_suspend_mac_and_wait(pi->sh->physhim);
4082		wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4083	}
4084	tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4085	tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4086
4087	if (tempsenseval1 > 255)
4088		avg = (int)(tempsenseval1 - 512);
4089	else
4090		avg = (int)tempsenseval1;
4091
4092	if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
4093		if (tempsenseval2 > 255)
4094			avg = (int)(avg - tempsenseval2 + 512);
4095		else
4096			avg = (int)(avg - tempsenseval2);
4097	} else {
4098		if (tempsenseval2 > 255)
4099			avg = (int)(avg + tempsenseval2 - 512);
4100		else
4101			avg = (int)(avg + tempsenseval2);
4102		avg = avg / 2;
4103	}
4104	if (avg < 0)
4105		avg = avg + 512;
4106
4107	if (pi_lcn->lcnphy_tempsense_option == 2)
4108		avg = tempsenseval1;
4109
4110	if (mode)
4111		wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4112
4113	if (mode == 1) {
4114
4115		mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4116
4117		udelay(100);
4118		mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4119
4120		if (!suspend)
4121			wlapi_enable_mac(pi->sh->physhim);
4122	}
4123	return (u16) avg;
4124}
4125
4126s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
4127{
4128	s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
4129	degree =
4130		((degree <<
4131		  10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
4132		/ LCN_TEMPSENSE_DEN;
4133	return (s8) degree;
4134}
4135
4136s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
4137{
4138	u16 vbatsenseval;
4139	s32 avg = 0;
4140	bool suspend = false;
4141
4142	if (mode == 1) {
4143		suspend = (0 == (bcma_read32(pi->d11core,
4144					     D11REGOFFS(maccontrol)) &
4145				 MCTL_EN_MAC));
4146		if (!suspend)
4147			wlapi_suspend_mac_and_wait(pi->sh->physhim);
4148		wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
4149	}
4150
4151	vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
4152
4153	if (vbatsenseval > 255)
4154		avg = (s32) (vbatsenseval - 512);
4155	else
4156		avg = (s32) vbatsenseval;
4157
4158	avg =	(avg * LCN_VBAT_SCALE_NOM +
4159		 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
4160
4161	if (mode == 1) {
4162		if (!suspend)
4163			wlapi_enable_mac(pi->sh->physhim);
4164	}
4165	return (s8) avg;
4166}
4167
4168static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
4169{
4170	u8 phybw40;
4171	phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4172
4173	mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
4174
4175	if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
4176	    (mode == AFE_CLK_INIT_MODE_TXRX2X))
4177		write_phy_reg(pi, 0x6d0, 0x7);
4178
4179	wlc_lcnphy_toggle_afe_pwdn(pi);
4180}
4181
4182static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4183{
4184}
4185
4186static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
4187{
4188	bool suspend;
4189	s8 index;
4190	u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4191	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4192	suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4193			 MCTL_EN_MAC));
4194	if (!suspend)
4195		wlapi_suspend_mac_and_wait(pi->sh->physhim);
4196	wlc_lcnphy_deaf_mode(pi, true);
4197	pi->phy_lastcal = pi->sh->now;
4198	pi->phy_forcecal = false;
4199	index = pi_lcn->lcnphy_current_index;
4200
4201	wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4202
4203	wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4204	wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4205	wlc_lcnphy_deaf_mode(pi, false);
4206	if (!suspend)
4207		wlapi_enable_mac(pi->sh->physhim);
4208
4209}
4210
4211static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
4212{
4213	bool suspend, full_cal;
4214	const struct lcnphy_rx_iqcomp *rx_iqcomp;
4215	int rx_iqcomp_sz;
4216	u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4217	s8 index;
4218	struct phytbl_info tab;
4219	s32 a1, b0, b1;
4220	s32 tssi, pwr, maxtargetpwr, mintargetpwr;
4221	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4222
4223	pi->phy_lastcal = pi->sh->now;
4224	pi->phy_forcecal = false;
4225	full_cal =
4226		(pi_lcn->lcnphy_full_cal_channel !=
4227		 CHSPEC_CHANNEL(pi->radio_chanspec));
4228	pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
4229	index = pi_lcn->lcnphy_current_index;
4230
4231	suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4232			 MCTL_EN_MAC));
4233	if (!suspend) {
4234		wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
4235		wlapi_suspend_mac_and_wait(pi->sh->physhim);
4236	}
4237
4238	wlc_lcnphy_deaf_mode(pi, true);
4239
4240	wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4241
4242	rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
4243	rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
4244
4245	if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4246		wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
4247	else
4248		wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
4249
4250	if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4251
4252		wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
4253
4254		b0 = pi->txpa_2g[0];
4255		b1 = pi->txpa_2g[1];
4256		a1 = pi->txpa_2g[2];
4257		maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
4258		mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
4259
4260		tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4261		tab.tbl_width = 32;
4262		tab.tbl_ptr = &pwr;
4263		tab.tbl_len = 1;
4264		tab.tbl_offset = 0;
4265		for (tssi = 0; tssi < 128; tssi++) {
4266			pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
4267			pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
4268			wlc_lcnphy_write_table(pi, &tab);
4269			tab.tbl_offset++;
4270		}
4271	}
4272
4273	wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4274	wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4275	wlc_lcnphy_deaf_mode(pi, false);
4276	if (!suspend)
4277		wlapi_enable_mac(pi->sh->physhim);
4278}
4279
4280void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
4281{
4282	u16 temp_new;
4283	int temp1, temp2, temp_diff;
4284	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4285
4286	switch (mode) {
4287	case PHY_PERICAL_CHAN:
4288		break;
4289	case PHY_FULLCAL:
4290		wlc_lcnphy_periodic_cal(pi);
4291		break;
4292	case PHY_PERICAL_PHYINIT:
4293		wlc_lcnphy_periodic_cal(pi);
4294		break;
4295	case PHY_PERICAL_WATCHDOG:
4296		if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4297			temp_new = wlc_lcnphy_tempsense(pi, 0);
4298			temp1 = LCNPHY_TEMPSENSE(temp_new);
4299			temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
4300			temp_diff = temp1 - temp2;
4301			if ((pi_lcn->lcnphy_cal_counter > 90) ||
4302			    (temp_diff > 60) || (temp_diff < -60)) {
4303				wlc_lcnphy_glacial_timer_based_cal(pi);
4304				wlc_2064_vco_cal(pi);
4305				pi_lcn->lcnphy_cal_temper = temp_new;
4306				pi_lcn->lcnphy_cal_counter = 0;
4307			} else
4308				pi_lcn->lcnphy_cal_counter++;
4309		}
4310		break;
4311	case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
4312		if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4313			wlc_lcnphy_tx_power_adjustment(
4314				(struct brcms_phy_pub *) pi);
4315		break;
4316	}
4317}
4318
4319void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
4320{
4321	s8 cck_offset;
4322	u16 status;
4323	status = (read_phy_reg(pi, 0x4ab));
4324	if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
4325	    (status  & (0x1 << 15))) {
4326		*ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
4327				   >> 0) >> 1);
4328
4329		if (wlc_phy_tpc_isenabled_lcnphy(pi))
4330			cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
4331		else
4332			cck_offset = 0;
4333
4334		*cck_pwr = *ofdm_pwr + cck_offset;
4335	} else {
4336		*cck_pwr = 0;
4337		*ofdm_pwr = 0;
4338	}
4339}
4340
4341void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4342{
4343	return;
4344
4345}
4346
4347void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
4348{
4349	s8 index;
4350	u16 index2;
4351	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
4352	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4353	u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4354	if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
4355	    SAVE_txpwrctrl) {
4356		index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
4357		index2 = (u16) (index * 2);
4358		mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
4359
4360		pi_lcn->lcnphy_current_index =
4361			(s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
4362	}
4363}
4364
4365static void
4366wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
4367			      const struct lcnphy_tx_gain_tbl_entry *gain_table)
4368{
4369	u32 j;
4370	struct phytbl_info tab;
4371	u32 val;
4372	u16 pa_gain;
4373	u16 gm_gain;
4374
4375	if (pi->sh->boardflags & BFL_FEM)
4376		pa_gain = 0x10;
4377	else
4378		pa_gain = 0x60;
4379	tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4380	tab.tbl_width = 32;
4381	tab.tbl_len = 1;
4382	tab.tbl_ptr = &val;
4383
4384	/* fixed gm_gain value for iPA */
4385	gm_gain = 15;
4386	for (j = 0; j < 128; j++) {
4387		if (pi->sh->boardflags & BFL_FEM)
4388			gm_gain = gain_table[j].gm;
4389		val = (((u32) pa_gain << 24) |
4390		       (gain_table[j].pad << 16) |
4391		       (gain_table[j].pga << 8) | gm_gain);
4392
4393		tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4394		wlc_lcnphy_write_table(pi, &tab);
4395
4396		val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4397		tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4398		wlc_lcnphy_write_table(pi, &tab);
4399	}
4400}
4401
4402static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
4403{
4404	struct phytbl_info tab;
4405	u32 val, bbmult, rfgain;
4406	u8 index;
4407	u8 scale_factor = 1;
4408	s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4409
4410	tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4411	tab.tbl_width = 32;
4412	tab.tbl_len = 1;
4413
4414	for (index = 0; index < 128; index++) {
4415		tab.tbl_ptr = &bbmult;
4416		tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4417		wlc_lcnphy_read_table(pi, &tab);
4418		bbmult = bbmult >> 20;
4419
4420		tab.tbl_ptr = &rfgain;
4421		tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4422		wlc_lcnphy_read_table(pi, &tab);
4423
4424		qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4425		qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4426
4427		if (qQ1 < qQ2) {
4428			temp2 = qm_shr16(temp2, qQ2 - qQ1);
4429			qQ = qQ1;
4430		} else {
4431			temp1 = qm_shr16(temp1, qQ1 - qQ2);
4432			qQ = qQ2;
4433		}
4434		temp = qm_sub16(temp1, temp2);
4435
4436		if (qQ >= 4)
4437			shift = qQ - 4;
4438		else
4439			shift = 4 - qQ;
4440
4441		val = (((index << shift) + (5 * temp) +
4442			(1 << (scale_factor + shift - 3))) >> (scale_factor +
4443							       shift - 2));
4444
4445		tab.tbl_ptr = &val;
4446		tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4447		wlc_lcnphy_write_table(pi, &tab);
4448	}
4449}
4450
4451static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
4452{
4453	or_phy_reg(pi, 0x805, 0x1);
4454
4455	mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4456
4457	mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4458
4459	write_phy_reg(pi, 0x414, 0x1e10);
4460	write_phy_reg(pi, 0x415, 0x0640);
4461
4462	mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4463
4464	or_phy_reg(pi, 0x44a, 0x44);
4465	write_phy_reg(pi, 0x44a, 0x80);
4466	mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4467
4468	mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4469
4470	if (!(pi->sh->boardrev < 0x1204))
4471		mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4472
4473	write_phy_reg(pi, 0x7d6, 0x0902);
4474	mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4475
4476	mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4477
4478	if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4479		mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4480
4481		mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4482
4483		mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4484
4485		mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4486
4487		mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4488
4489		mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4490		mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4491		mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4492		mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4493		mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4494
4495		mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4496
4497		wlc_lcnphy_clear_tx_power_offsets(pi);
4498		mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4499
4500	}
4501}
4502
4503static void wlc_lcnphy_rcal(struct brcms_phy *pi)
4504{
4505	u8 rcal_value;
4506
4507	and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4508
4509	or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4510	or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4511
4512	or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4513	or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4514
4515	or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4516
4517	or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4518	mdelay(5);
4519	SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4520
4521	if (wlc_radio_2064_rcal_done(pi)) {
4522		rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4523		rcal_value = rcal_value & 0x1f;
4524	}
4525
4526	and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4527
4528	and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4529}
4530
4531static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
4532{
4533	u8 dflt_rc_cal_val;
4534	u16 flt_val;
4535
4536	dflt_rc_cal_val = 7;
4537	if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4538		dflt_rc_cal_val = 11;
4539	flt_val =
4540		(dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4541		(dflt_rc_cal_val);
4542	write_phy_reg(pi, 0x933, flt_val);
4543	write_phy_reg(pi, 0x934, flt_val);
4544	write_phy_reg(pi, 0x935, flt_val);
4545	write_phy_reg(pi, 0x936, flt_val);
4546	write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4547
4548	return;
4549}
4550
4551static void wlc_radio_2064_init(struct brcms_phy *pi)
4552{
4553	u32 i;
4554	const struct lcnphy_radio_regs *lcnphyregs = NULL;
4555
4556	lcnphyregs = lcnphy_radio_regs_2064;
4557
4558	for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4559		if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4560			write_radio_reg(pi,
4561					((lcnphyregs[i].address & 0x3fff) |
4562					 RADIO_DEFAULT_CORE),
4563					(u16) lcnphyregs[i].init_a);
4564		else if (lcnphyregs[i].do_init_g)
4565			write_radio_reg(pi,
4566					((lcnphyregs[i].address & 0x3fff) |
4567					 RADIO_DEFAULT_CORE),
4568					(u16) lcnphyregs[i].init_g);
4569
4570	write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4571	write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4572
4573	write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4574
4575	write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4576
4577	if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4578
4579		write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4580		write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4581		write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4582	}
4583
4584	write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4585	write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4586
4587	mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4588
4589	mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4590
4591	mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4592
4593	mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4594
4595	mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4596
4597	write_phy_reg(pi, 0x4ea, 0x4688);
4598
4599	if (pi->sh->boardflags & BFL_FEM)
4600		mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4601	else
4602		mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);
4603
4604	mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4605
4606	mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4607
4608	wlc_lcnphy_set_tx_locc(pi, 0);
4609
4610	wlc_lcnphy_rcal(pi);
4611
4612	wlc_lcnphy_rc_cal(pi);
4613
4614	if (!(pi->sh->boardflags & BFL_FEM)) {
4615		write_radio_reg(pi, RADIO_2064_REG032, 0x6f);
4616		write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4617		write_radio_reg(pi, RADIO_2064_REG039, 0xe);
4618	}
4619
4620}
4621
4622static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4623{
4624	wlc_radio_2064_init(pi);
4625}
4626
4627static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
4628{
4629	uint idx;
4630	u8 phybw40;
4631	struct phytbl_info tab;
4632	const struct phytbl_info *tb;
4633	u32 val;
4634
4635	phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4636
4637	for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
4638		wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4639
4640	if (pi->sh->boardflags & BFL_FEM_BT) {
4641		tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4642		tab.tbl_width = 16;
4643		tab.tbl_ptr = &val;
4644		tab.tbl_len = 1;
4645		val = 100;
4646		tab.tbl_offset = 4;
4647		wlc_lcnphy_write_table(pi, &tab);
4648	}
4649
4650	if (!(pi->sh->boardflags & BFL_FEM)) {
4651		tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4652		tab.tbl_width = 16;
4653		tab.tbl_ptr = &val;
4654		tab.tbl_len = 1;
4655
4656		val = 150;
4657		tab.tbl_offset = 0;
4658		wlc_lcnphy_write_table(pi, &tab);
4659
4660		val = 220;
4661		tab.tbl_offset = 1;
4662		wlc_lcnphy_write_table(pi, &tab);
4663	}
4664
4665	if (CHSPEC_IS2G(pi->radio_chanspec)) {
4666		if (pi->sh->boardflags & BFL_FEM)
4667			wlc_lcnphy_load_tx_gain_table(
4668				pi,
4669				dot11lcnphy_2GHz_extPA_gaintable_rev0);
4670		else
4671			wlc_lcnphy_load_tx_gain_table(
4672				pi,
4673				dot11lcnphy_2GHz_gaintable_rev0);
4674	}
4675
4676	if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4677		int l;
4678
4679		if (CHSPEC_IS2G(pi->radio_chanspec)) {
4680			l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4681			if (pi->sh->boardflags & BFL_EXTLNA)
4682				tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
4683			else
4684				tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
4685		} else {
4686			l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4687			if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4688				tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
4689			else
4690				tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
4691		}
4692
4693		for (idx = 0; idx < l; idx++)
4694			wlc_lcnphy_write_table(pi, &tb[idx]);
4695	}
4696
4697	if (pi->sh->boardflags & BFL_FEM) {
4698		if (pi->sh->boardflags & BFL_FEM_BT) {
4699			if (pi->sh->boardrev < 0x1250)
4700				tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
4701			else
4702				tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
4703		} else {
4704			tb = &dot11lcn_sw_ctrl_tbl_info_4313_epa;
4705		}
4706	} else {
4707		if (pi->sh->boardflags & BFL_FEM_BT)
4708			tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa;
4709		else
4710			tb = &dot11lcn_sw_ctrl_tbl_info_4313;
4711	}
4712	wlc_lcnphy_write_table(pi, tb);
4713	wlc_lcnphy_load_rfpower(pi);
4714
4715	wlc_lcnphy_clear_papd_comptable(pi);
4716}
4717
4718static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
4719{
4720	u16 afectrl1;
4721	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4722
4723	write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4724
4725	write_phy_reg(pi, 0x43b, 0x0);
4726	write_phy_reg(pi, 0x43c, 0x0);
4727	write_phy_reg(pi, 0x44c, 0x0);
4728	write_phy_reg(pi, 0x4e6, 0x0);
4729	write_phy_reg(pi, 0x4f9, 0x0);
4730	write_phy_reg(pi, 0x4b0, 0x0);
4731	write_phy_reg(pi, 0x938, 0x0);
4732	write_phy_reg(pi, 0x4b0, 0x0);
4733	write_phy_reg(pi, 0x44e, 0);
4734
4735	or_phy_reg(pi, 0x567, 0x03);
4736
4737	or_phy_reg(pi, 0x44a, 0x44);
4738	write_phy_reg(pi, 0x44a, 0x80);
4739
4740	if (!(pi->sh->boardflags & BFL_FEM))
4741		wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4742
4743	if (0) {
4744		afectrl1 = 0;
4745		afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4746				  (pi_lcn->lcnphy_rssi_vc << 4) |
4747				  (pi_lcn->lcnphy_rssi_gs << 10));
4748		write_phy_reg(pi, 0x43e, afectrl1);
4749	}
4750
4751	mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4752	if (pi->sh->boardflags & BFL_FEM) {
4753		mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4754
4755		write_phy_reg(pi, 0x910, 0x1);
4756	}
4757
4758	mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4759	mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4760	mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4761
4762}
4763
4764static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
4765{
4766	if (CHSPEC_IS5G(pi->radio_chanspec)) {
4767		mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4768		mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4769	}
4770}
4771
4772static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
4773{
4774	s16 temp;
4775	struct phytbl_info tab;
4776	u32 tableBuffer[2];
4777	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4778
4779	temp = (s16) read_phy_reg(pi, 0x4df);
4780	pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4781
4782	if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4783		pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4784
4785	pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4786
4787	if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4788		pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4789
4790	tab.tbl_ptr = tableBuffer;
4791	tab.tbl_len = 2;
4792	tab.tbl_id = 17;
4793	tab.tbl_offset = 59;
4794	tab.tbl_width = 32;
4795	wlc_lcnphy_read_table(pi, &tab);
4796
4797	if (tableBuffer[0] > 63)
4798		tableBuffer[0] -= 128;
4799	pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4800
4801	if (tableBuffer[1] > 63)
4802		tableBuffer[1] -= 128;
4803	pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4804
4805	temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
4806	if (temp > 127)
4807		temp -= 256;
4808	pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4809
4810	pi_lcn->lcnphy_Med_Low_Gain_db =
4811		(read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
4812	pi_lcn->lcnphy_Very_Low_Gain_db =
4813		(read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
4814
4815	tab.tbl_ptr = tableBuffer;
4816	tab.tbl_len = 2;
4817	tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4818	tab.tbl_offset = 28;
4819	tab.tbl_width = 32;
4820	wlc_lcnphy_read_table(pi, &tab);
4821
4822	pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4823	pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4824
4825}
4826
4827static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
4828{
4829
4830	wlc_lcnphy_tbl_init(pi);
4831	wlc_lcnphy_rev0_baseband_init(pi);
4832	if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4833		wlc_lcnphy_rev2_baseband_init(pi);
4834	wlc_lcnphy_bu_tweaks(pi);
4835}
4836
4837void wlc_phy_init_lcnphy(struct brcms_phy *pi)
4838{
4839	u8 phybw40;
4840	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4841	phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4842
4843	pi_lcn->lcnphy_cal_counter = 0;
4844	pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
4845
4846	or_phy_reg(pi, 0x44a, 0x80);
4847	and_phy_reg(pi, 0x44a, 0x7f);
4848
4849	wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
4850
4851	write_phy_reg(pi, 0x60a, 160);
4852
4853	write_phy_reg(pi, 0x46a, 25);
4854
4855	wlc_lcnphy_baseband_init(pi);
4856
4857	wlc_lcnphy_radio_init(pi);
4858
4859	if (CHSPEC_IS2G(pi->radio_chanspec))
4860		wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
4861
4862	wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
4863
4864	bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9);
4865
4866	bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0,
4867				    0x03CDDDDD);
4868
4869	if ((pi->sh->boardflags & BFL_FEM)
4870	    && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4871		wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
4872
4873	wlc_lcnphy_agc_temp_init(pi);
4874
4875	wlc_lcnphy_temp_adj(pi);
4876
4877	mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4878
4879	udelay(100);
4880	mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4881
4882	wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
4883	pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
4884	wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
4885}
4886
4887static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
4888{
4889	s8 txpwr = 0;
4890	int i;
4891	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4892	struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
4893
4894	if (CHSPEC_IS2G(pi->radio_chanspec)) {
4895		u16 cckpo = 0;
4896		u32 offset_ofdm, offset_mcs;
4897
4898		pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
4899
4900		pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
4901
4902		pi->txpa_2g[0] = sprom->pa0b0;
4903		pi->txpa_2g[1] = sprom->pa0b1;
4904		pi->txpa_2g[2] = sprom->pa0b2;
4905
4906		pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
4907		pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
4908		pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
4909
4910		pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4911		pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4912		pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4913
4914		pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
4915		pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
4916		pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
4917
4918		txpwr = sprom->core_pwr_info[0].maxpwr_2g;
4919		pi->tx_srom_max_2g = txpwr;
4920
4921		for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4922			pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4923			pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4924		}
4925
4926		cckpo = sprom->cck2gpo;
4927		offset_ofdm = sprom->ofdm2gpo;
4928		if (cckpo) {
4929			uint max_pwr_chan = txpwr;
4930
4931			for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4932				pi->tx_srom_max_rate_2g[i] =
4933					max_pwr_chan - ((cckpo & 0xf) * 2);
4934				cckpo >>= 4;
4935			}
4936
4937			for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4938				pi->tx_srom_max_rate_2g[i] =
4939					max_pwr_chan -
4940					((offset_ofdm & 0xf) * 2);
4941				offset_ofdm >>= 4;
4942			}
4943		} else {
4944			u8 opo = 0;
4945
4946			opo = sprom->opo;
4947
4948			for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
4949				pi->tx_srom_max_rate_2g[i] = txpwr;
4950
4951			for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4952				pi->tx_srom_max_rate_2g[i] = txpwr -
4953						((offset_ofdm & 0xf) * 2);
4954				offset_ofdm >>= 4;
4955			}
4956			offset_mcs = sprom->mcs2gpo[1] << 16;
4957			offset_mcs |= sprom->mcs2gpo[0];
4958			pi_lcn->lcnphy_mcs20_po = offset_mcs;
4959			for (i = TXP_FIRST_SISO_MCS_20;
4960			     i <= TXP_LAST_SISO_MCS_20; i++) {
4961				pi->tx_srom_max_rate_2g[i] =
4962					txpwr - ((offset_mcs & 0xf) * 2);
4963				offset_mcs >>= 4;
4964			}
4965		}
4966
4967		pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
4968		pi_lcn->lcnphy_measPower = sprom->measpower;
4969		pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
4970		pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
4971		pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
4972		pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
4973		pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
4974		pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
4975		if (sprom->ant_available_bg > 1)
4976			wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
4977				sprom->ant_available_bg);
4978	}
4979	pi_lcn->lcnphy_cck_dig_filt_type = -1;
4980
4981	return true;
4982}
4983
4984void wlc_2064_vco_cal(struct brcms_phy *pi)
4985{
4986	u8 calnrst;
4987
4988	mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4989	calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4990	write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4991	udelay(1);
4992	write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4993	udelay(1);
4994	write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4995	udelay(300);
4996	mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4997}
4998
4999bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
5000{
5001	if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
5002		return false;
5003	else
5004		return (LCNPHY_TX_PWR_CTRL_HW ==
5005			wlc_lcnphy_get_tx_pwr_ctrl((pi)));
5006}
5007
5008void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
5009{
5010	u16 pwr_ctrl;
5011	if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5012		wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5013	} else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
5014		pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
5015		wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
5016		wlc_lcnphy_txpower_recalc_target(pi);
5017		wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5018	}
5019}
5020
5021void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
5022{
5023	u8 channel = CHSPEC_CHANNEL(chanspec);
5024
5025	wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec);
5026
5027	wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
5028
5029	or_phy_reg(pi, 0x44a, 0x44);
5030	write_phy_reg(pi, 0x44a, 0x80);
5031
5032	wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
5033	udelay(1000);
5034
5035	wlc_lcnphy_toggle_afe_pwdn(pi);
5036
5037	write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
5038	write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
5039
5040	if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
5041		mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
5042
5043		wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
5044	} else {
5045		mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
5046
5047		wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
5048	}
5049
5050	if (pi->sh->boardflags & BFL_FEM)
5051		wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
5052	else
5053		wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
5054
5055	mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
5056	if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
5057		wlc_lcnphy_tssi_setup(pi);
5058}
5059
5060void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
5061{
5062	kfree(pi->u.pi_lcnphy);
5063}
5064
5065bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
5066{
5067	struct brcms_phy_lcnphy *pi_lcn;
5068
5069	pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
5070	if (pi->u.pi_lcnphy == NULL)
5071		return false;
5072
5073	pi_lcn = pi->u.pi_lcnphy;
5074
5075	if (0 == (pi->sh->boardflags & BFL_NOPA)) {
5076		pi->hwpwrctrl = true;
5077		pi->hwpwrctrl_capable = true;
5078	}
5079
5080	pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc);
5081	pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5082
5083	pi->pi_fptr.init = wlc_phy_init_lcnphy;
5084	pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5085	pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5086	pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5087	pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5088	pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5089	pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5090	pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5091	pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5092
5093	if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5094		return false;
5095
5096	if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5097		if (pi_lcn->lcnphy_tempsense_option == 3) {
5098			pi->hwpwrctrl = true;
5099			pi->hwpwrctrl_capable = true;
5100			pi->temppwrctrl_capable = false;
5101		} else {
5102			pi->hwpwrctrl = false;
5103			pi->hwpwrctrl_capable = false;
5104			pi->temppwrctrl_capable = true;
5105		}
5106	}
5107
5108	return true;
5109}
5110
5111static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
5112{
5113	u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5114
5115	trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5116	ext_lna = (u16) (gain >> 29) & 0x01;
5117	lna1 = (u16) (gain >> 0) & 0x0f;
5118	lna2 = (u16) (gain >> 4) & 0x0f;
5119	tia = (u16) (gain >> 8) & 0xf;
5120	biq0 = (u16) (gain >> 12) & 0xf;
5121	biq1 = (u16) (gain >> 16) & 0xf;
5122
5123	gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5124			  ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5125			  ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5126	gain16_19 = biq1;
5127
5128	mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5129	mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5130	mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5131	mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5132	mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5133
5134	if (CHSPEC_IS2G(pi->radio_chanspec)) {
5135		mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5136		mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5137	}
5138	wlc_lcnphy_rx_gain_override_enable(pi, true);
5139}
5140
5141static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
5142{
5143	u32 received_power = 0;
5144	s32 max_index = 0;
5145	u32 gain_code = 0;
5146	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5147
5148	max_index = 36;
5149	if (*gain_index >= 0)
5150		gain_code = lcnphy_23bitgaincode_table[*gain_index];
5151
5152	if (-1 == *gain_index) {
5153		*gain_index = 0;
5154		while ((*gain_index <= (s32) max_index)
5155		       && (received_power < 700)) {
5156			wlc_lcnphy_set_rx_gain(pi,
5157					       lcnphy_23bitgaincode_table
5158					       [*gain_index]);
5159			received_power =
5160				wlc_lcnphy_measure_digital_power(
5161					pi,
5162					pi_lcn->
5163					lcnphy_noise_samples);
5164			(*gain_index)++;
5165		}
5166		(*gain_index)--;
5167	} else {
5168		wlc_lcnphy_set_rx_gain(pi, gain_code);
5169		received_power =
5170			wlc_lcnphy_measure_digital_power(pi,
5171							 pi_lcn->
5172							 lcnphy_noise_samples);
5173	}
5174
5175	return received_power;
5176}
5177
5178s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
5179{
5180	s32 gain = 0;
5181	s32 nominal_power_db;
5182	s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5183	    input_power_db;
5184	s32 received_power, temperature;
5185	u32 power;
5186	u32 msb1, msb2, val1, val2, diff1, diff2;
5187	uint freq;
5188	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5189
5190	received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5191
5192	gain = lcnphy_gain_table[gain_index];
5193
5194	nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5195
5196	power = (received_power * 16);
5197	msb1 = ffs(power) - 1;
5198	msb2 = msb1 + 1;
5199	val1 = 1 << msb1;
5200	val2 = 1 << msb2;
5201	diff1 = (power - val1);
5202	diff2 = (val2 - power);
5203	if (diff1 < diff2)
5204		log_val = msb1;
5205	else
5206		log_val = msb2;
5207
5208	log_val = log_val * 3;
5209
5210	gain_mismatch = (nominal_power_db / 2) - (log_val);
5211
5212	desired_gain = gain + gain_mismatch;
5213
5214	input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5215
5216	if (input_power_offset_db > 127)
5217		input_power_offset_db -= 256;
5218
5219	input_power_db = input_power_offset_db - desired_gain;
5220
5221	input_power_db =
5222		input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5223
5224	freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5225	if ((freq > 2427) && (freq <= 2467))
5226		input_power_db = input_power_db - 1;
5227
5228	temperature = pi_lcn->lcnphy_lastsensed_temperature;
5229
5230	if ((temperature - 15) < -30)
5231		input_power_db =
5232			input_power_db +
5233			(((temperature - 10 - 25) * 286) >> 12) -
5234			7;
5235	else if ((temperature - 15) < 4)
5236		input_power_db =
5237			input_power_db +
5238			(((temperature - 10 - 25) * 286) >> 12) -
5239			3;
5240	else
5241		input_power_db = input_power_db +
5242					(((temperature - 10 - 25) * 286) >> 12);
5243
5244	wlc_lcnphy_rx_gain_override_enable(pi, 0);
5245
5246	return input_power_db;
5247}
5248