cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy_lcn.c (130257B)


      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, (u16) ~(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}