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