diff options
Diffstat (limited to 'drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c')
-rw-r--r-- | drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c | 5247 |
1 files changed, 5247 insertions, 0 deletions
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c new file mode 100644 index 000000000000..93d4cde0eb31 --- /dev/null +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c @@ -0,0 +1,5247 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/cordic.h> + +#include <pmu.h> +#include <d11.h> +#include <phy_shim.h> +#include "phy_qmath.h" +#include "phy_hal.h" +#include "phy_radio.h" +#include "phytbl_lcn.h" +#include "phy_lcn.h" + +#define PLL_2064_NDIV 90 +#define PLL_2064_LOW_END_VCO 3000 +#define PLL_2064_LOW_END_KVCO 27 +#define PLL_2064_HIGH_END_VCO 4200 +#define PLL_2064_HIGH_END_KVCO 68 +#define PLL_2064_LOOP_BW_DOUBLER 200 +#define PLL_2064_D30_DOUBLER 10500 +#define PLL_2064_LOOP_BW 260 +#define PLL_2064_D30 8000 +#define PLL_2064_CAL_REF_TO 8 +#define PLL_2064_MHZ 1000000 +#define PLL_2064_OPEN_LOOP_DELAY 5 + +#define TEMPSENSE 1 +#define VBATSENSE 2 + +#define NOISE_IF_UPD_CHK_INTERVAL 1 +#define NOISE_IF_UPD_RST_INTERVAL 60 +#define NOISE_IF_UPD_THRESHOLD_CNT 1 +#define NOISE_IF_UPD_TRHRESHOLD 50 +#define NOISE_IF_UPD_TIMEOUT 1000 +#define NOISE_IF_OFF 0 +#define NOISE_IF_CHK 1 +#define NOISE_IF_ON 2 + +#define PAPD_BLANKING_PROFILE 3 +#define PAPD2LUT 0 +#define PAPD_CORR_NORM 0 +#define PAPD_BLANKING_THRESHOLD 0 +#define PAPD_STOP_AFTER_LAST_UPDATE 0 + +#define LCN_TARGET_PWR 60 + +#define LCN_VBAT_OFFSET_433X 34649679 +#define LCN_VBAT_SLOPE_433X 8258032 + +#define LCN_VBAT_SCALE_NOM 53 +#define LCN_VBAT_SCALE_DEN 432 + +#define LCN_TEMPSENSE_OFFSET 80812 +#define LCN_TEMPSENSE_DEN 2647 + +#define LCN_BW_LMT 200 +#define LCN_CUR_LMT 1250 +#define LCN_MULT 1 +#define LCN_VCO_DIV 30 +#define LCN_OFFSET 680 +#define LCN_FACT 490 +#define LCN_CUR_DIV 2640 + +#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \ + (0 + 8) +#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \ + (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT) + +#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \ + (0 + 8) +#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \ + (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT) + +#define wlc_lcnphy_enable_tx_gain_override(pi) \ + wlc_lcnphy_set_tx_gain_override(pi, true) +#define wlc_lcnphy_disable_tx_gain_override(pi) \ + wlc_lcnphy_set_tx_gain_override(pi, false) + +#define wlc_lcnphy_iqcal_active(pi) \ + (read_phy_reg((pi), 0x451) & \ + ((0x1 << 15) | (0x1 << 14))) + +#define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13)) +#define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \ + (pi->temppwrctrl_capable) +#define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \ + (pi->hwpwrctrl_capable) + +#define SWCTRL_BT_TX 0x18 +#define SWCTRL_OVR_DISABLE 0x40 + +#define AFE_CLK_INIT_MODE_TXRX2X 1 +#define AFE_CLK_INIT_MODE_PAPD 0 + +#define LCNPHY_TBL_ID_IQLOCAL 0x00 + +#define LCNPHY_TBL_ID_RFSEQ 0x08 +#define LCNPHY_TBL_ID_GAIN_IDX 0x0d +#define LCNPHY_TBL_ID_SW_CTRL 0x0f +#define LCNPHY_TBL_ID_GAIN_TBL 0x12 +#define LCNPHY_TBL_ID_SPUR 0x14 +#define LCNPHY_TBL_ID_SAMPLEPLAY 0x15 +#define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16 + +#define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832 +#define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128 +#define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192 +#define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320 +#define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448 +#define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576 + +#define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140 + +#define LCNPHY_TX_PWR_CTRL_START_NPT 1 +#define LCNPHY_TX_PWR_CTRL_MAX_NPT 7 + +#define LCNPHY_NOISE_SAMPLES_DEFAULT 5000 + +#define LCNPHY_ACI_DETECT_START 1 +#define LCNPHY_ACI_DETECT_PROGRESS 2 +#define LCNPHY_ACI_DETECT_STOP 3 + +#define LCNPHY_ACI_CRSHIFRMLO_TRSH 100 +#define LCNPHY_ACI_GLITCH_TRSH 2000 +#define LCNPHY_ACI_TMOUT 250 +#define LCNPHY_ACI_DETECT_TIMEOUT 2 +#define LCNPHY_ACI_START_DELAY 0 + +#define wlc_lcnphy_tx_gain_override_enabled(pi) \ + (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6))) + +#define wlc_lcnphy_total_tx_frames(pi) \ + wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \ + offsetof(struct macstat, txallfrm)) + +struct lcnphy_txgains { + u16 gm_gain; + u16 pga_gain; + u16 pad_gain; + u16 dac_gain; +}; + +enum lcnphy_cal_mode { + LCNPHY_CAL_FULL, + LCNPHY_CAL_RECAL, + LCNPHY_CAL_CURRECAL, + LCNPHY_CAL_DIGCAL, + LCNPHY_CAL_GCTRL +}; + +struct lcnphy_rx_iqcomp { + u8 chan; + s16 a; + s16 b; +}; + +struct lcnphy_spb_tone { + s16 re; + s16 im; +}; + +struct lcnphy_unsign16_struct { + u16 re; + u16 im; +}; + +struct lcnphy_iq_est { + u32 iq_prod; + u32 i_pwr; + u32 q_pwr; +}; + +struct lcnphy_sfo_cfg { + u16 ptcentreTs20; + u16 ptcentreFactor; +}; + +enum lcnphy_papd_cal_type { + LCNPHY_PAPD_CAL_CW, + LCNPHY_PAPD_CAL_OFDM +}; + +typedef u16 iqcal_gain_params_lcnphy[9]; + +static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + +static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = { + tbl_iqcal_gainparams_lcnphy_2G, +}; + +static const u16 iqcal_gainparams_numgains_lcnphy[1] = { + ARRAY_SIZE(tbl_iqcal_gainparams_lcnphy_2G), +}; + +static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = { + {965, 1087}, + {967, 1085}, + {969, 1082}, + {971, 1080}, + {973, 1078}, + {975, 1076}, + {977, 1073}, + {979, 1071}, + {981, 1069}, + {983, 1067}, + {985, 1065}, + {987, 1063}, + {989, 1060}, + {994, 1055} +}; + +static const +u16 lcnphy_iqcal_loft_gainladder[] = { + ((2 << 8) | 0), + ((3 << 8) | 0), + ((4 << 8) | 0), + ((6 << 8) | 0), + ((8 << 8) | 0), + ((11 << 8) | 0), + ((16 << 8) | 0), + ((16 << 8) | 1), + ((16 << 8) | 2), + ((16 << 8) | 3), + ((16 << 8) | 4), + ((16 << 8) | 5), + ((16 << 8) | 6), + ((16 << 8) | 7), + ((23 << 8) | 7), + ((32 << 8) | 7), + ((45 << 8) | 7), + ((64 << 8) | 7), + ((91 << 8) | 7), + ((128 << 8) | 7) +}; + +static const +u16 lcnphy_iqcal_ir_gainladder[] = { + ((1 << 8) | 0), + ((2 << 8) | 0), + ((4 << 8) | 0), + ((6 << 8) | 0), + ((8 << 8) | 0), + ((11 << 8) | 0), + ((16 << 8) | 0), + ((23 << 8) | 0), + ((32 << 8) | 0), + ((45 << 8) | 0), + ((64 << 8) | 0), + ((64 << 8) | 1), + ((64 << 8) | 2), + ((64 << 8) | 3), + ((64 << 8) | 4), + ((64 << 8) | 5), + ((64 << 8) | 6), + ((64 << 8) | 7), + ((91 << 8) | 7), + ((128 << 8) | 7) +}; + +static const +struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = { + {88, 0}, + {73, 49}, + {34, 81}, + {-17, 86}, + {-62, 62}, + {-86, 17}, + {-81, -34}, + {-49, -73}, + {0, -88}, + {49, -73}, + {81, -34}, + {86, 17}, + {62, 62}, + {17, 86}, + {-34, 81}, + {-73, 49}, + {-88, 0}, + {-73, -49}, + {-34, -81}, + {17, -86}, + {62, -62}, + {86, -17}, + {81, 34}, + {49, 73}, + {0, 88}, + {-49, 73}, + {-81, 34}, + {-86, -17}, + {-62, -62}, + {-17, -86}, + {34, -81}, + {73, -49}, +}; + +static const +u16 iqlo_loopback_rf_regs[20] = { + RADIO_2064_REG036, + RADIO_2064_REG11A, + RADIO_2064_REG03A, + RADIO_2064_REG025, + RADIO_2064_REG028, + RADIO_2064_REG005, + RADIO_2064_REG112, + RADIO_2064_REG0FF, + RADIO_2064_REG11F, + RADIO_2064_REG00B, + RADIO_2064_REG113, + RADIO_2064_REG007, + RADIO_2064_REG0FC, + RADIO_2064_REG0FD, + RADIO_2064_REG012, + RADIO_2064_REG057, + RADIO_2064_REG059, + RADIO_2064_REG05C, + RADIO_2064_REG078, + RADIO_2064_REG092, +}; + +static const +u16 tempsense_phy_regs[14] = { + 0x503, + 0x4a4, + 0x4d0, + 0x4d9, + 0x4da, + 0x4a6, + 0x938, + 0x939, + 0x4d8, + 0x4d0, + 0x4d7, + 0x4a5, + 0x40d, + 0x4a2, +}; + +static const +u16 rxiq_cal_rf_reg[11] = { + RADIO_2064_REG098, + RADIO_2064_REG116, + RADIO_2064_REG12C, + RADIO_2064_REG06A, + RADIO_2064_REG00B, + RADIO_2064_REG01B, + RADIO_2064_REG113, + RADIO_2064_REG01D, + RADIO_2064_REG114, + RADIO_2064_REG02E, + RADIO_2064_REG12A, +}; + +static const +struct lcnphy_rx_iqcomp lcnphy_rx_iqcomp_table_rev0[] = { + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {5, 0, 0}, + {6, 0, 0}, + {7, 0, 0}, + {8, 0, 0}, + {9, 0, 0}, + {10, 0, 0}, + {11, 0, 0}, + {12, 0, 0}, + {13, 0, 0}, + {14, 0, 0}, + {34, 0, 0}, + {38, 0, 0}, + {42, 0, 0}, + {46, 0, 0}, + {36, 0, 0}, + {40, 0, 0}, + {44, 0, 0}, + {48, 0, 0}, + {52, 0, 0}, + {56, 0, 0}, + {60, 0, 0}, + {64, 0, 0}, + {100, 0, 0}, + {104, 0, 0}, + {108, 0, 0}, + {112, 0, 0}, + {116, 0, 0}, + {120, 0, 0}, + {124, 0, 0}, + {128, 0, 0}, + {132, 0, 0}, + {136, 0, 0}, + {140, 0, 0}, + {149, 0, 0}, + {153, 0, 0}, + {157, 0, 0}, + {161, 0, 0}, + {165, 0, 0}, + {184, 0, 0}, + {188, 0, 0}, + {192, 0, 0}, + {196, 0, 0}, + {200, 0, 0}, + {204, 0, 0}, + {208, 0, 0}, + {212, 0, 0}, + {216, 0, 0}, +}; + +static const u32 lcnphy_23bitgaincode_table[] = { + 0x200100, + 0x200200, + 0x200004, + 0x200014, + 0x200024, + 0x200034, + 0x200134, + 0x200234, + 0x200334, + 0x200434, + 0x200037, + 0x200137, + 0x200237, + 0x200337, + 0x200437, + 0x000035, + 0x000135, + 0x000235, + 0x000037, + 0x000137, + 0x000237, + 0x000337, + 0x00013f, + 0x00023f, + 0x00033f, + 0x00034f, + 0x00044f, + 0x00144f, + 0x00244f, + 0x00254f, + 0x00354f, + 0x00454f, + 0x00464f, + 0x01464f, + 0x02464f, + 0x03464f, + 0x04464f, +}; + +static const s8 lcnphy_gain_table[] = { + -16, + -13, + 10, + 7, + 4, + 0, + 3, + 6, + 9, + 12, + 15, + 18, + 21, + 24, + 27, + 30, + 33, + 36, + 39, + 42, + 45, + 48, + 50, + 53, + 56, + 59, + 62, + 65, + 68, + 71, + 74, + 77, + 80, + 83, + 86, + 89, + 92, +}; + +static const s8 lcnphy_gain_index_offset_for_rssi[] = { + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 8, + 7, + 7, + 6, + 7, + 7, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -2, + -2, + -2 +}; + +struct chan_info_2064_lcnphy { + uint chan; + uint freq; + u8 logen_buftune; + u8 logen_rccr_tx; + u8 txrf_mix_tune_ctrl; + u8 pa_input_tune_g; + u8 logen_rccr_rx; + u8 pa_rxrf_lna1_freq_tune; + u8 pa_rxrf_lna2_freq_tune; + u8 rxrf_rxrf_spare1; +}; + +static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = { + {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, +}; + +static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = { + {0x00, 0, 0, 0, 0}, + {0x01, 0x64, 0x64, 0, 0}, + {0x02, 0x20, 0x20, 0, 0}, + {0x03, 0x66, 0x66, 0, 0}, + {0x04, 0xf8, 0xf8, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0x10, 0x10, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0x37, 0x37, 0, 0}, + {0x0B, 0x6, 0x6, 0, 0}, + {0x0C, 0x55, 0x55, 0, 0}, + {0x0D, 0x8b, 0x8b, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0x5, 0x5, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0xe, 0xe, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0xb, 0xb, 0, 0}, + {0x14, 0x2, 0x2, 0, 0}, + {0x15, 0x12, 0x12, 0, 0}, + {0x16, 0x12, 0x12, 0, 0}, + {0x17, 0xc, 0xc, 0, 0}, + {0x18, 0xc, 0xc, 0, 0}, + {0x19, 0xc, 0xc, 0, 0}, + {0x1A, 0x8, 0x8, 0, 0}, + {0x1B, 0x2, 0x2, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0x1, 0x1, 0, 0}, + {0x1E, 0x12, 0x12, 0, 0}, + {0x1F, 0x6e, 0x6e, 0, 0}, + {0x20, 0x2, 0x2, 0, 0}, + {0x21, 0x23, 0x23, 0, 0}, + {0x22, 0x8, 0x8, 0, 0}, + {0x23, 0, 0, 0, 0}, + {0x24, 0, 0, 0, 0}, + {0x25, 0xc, 0xc, 0, 0}, + {0x26, 0x33, 0x33, 0, 0}, + {0x27, 0x55, 0x55, 0, 0}, + {0x28, 0, 0, 0, 0}, + {0x29, 0x30, 0x30, 0, 0}, + {0x2A, 0xb, 0xb, 0, 0}, + {0x2B, 0x1b, 0x1b, 0, 0}, + {0x2C, 0x3, 0x3, 0, 0}, + {0x2D, 0x1b, 0x1b, 0, 0}, + {0x2E, 0, 0, 0, 0}, + {0x2F, 0x20, 0x20, 0, 0}, + {0x30, 0xa, 0xa, 0, 0}, + {0x31, 0, 0, 0, 0}, + {0x32, 0x62, 0x62, 0, 0}, + {0x33, 0x19, 0x19, 0, 0}, + {0x34, 0x33, 0x33, 0, 0}, + {0x35, 0x77, 0x77, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0x70, 0x70, 0, 0}, + {0x38, 0x3, 0x3, 0, 0}, + {0x39, 0xf, 0xf, 0, 0}, + {0x3A, 0x6, 0x6, 0, 0}, + {0x3B, 0xcf, 0xcf, 0, 0}, + {0x3C, 0x1a, 0x1a, 0, 0}, + {0x3D, 0x6, 0x6, 0, 0}, + {0x3E, 0x42, 0x42, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0xfb, 0xfb, 0, 0}, + {0x41, 0x9a, 0x9a, 0, 0}, + {0x42, 0x7a, 0x7a, 0, 0}, + {0x43, 0x29, 0x29, 0, 0}, + {0x44, 0, 0, 0, 0}, + {0x45, 0x8, 0x8, 0, 0}, + {0x46, 0xce, 0xce, 0, 0}, + {0x47, 0x27, 0x27, 0, 0}, + {0x48, 0x62, 0x62, 0, 0}, + {0x49, 0x6, 0x6, 0, 0}, + {0x4A, 0x58, 0x58, 0, 0}, + {0x4B, 0xf7, 0xf7, 0, 0}, + {0x4C, 0, 0, 0, 0}, + {0x4D, 0xb3, 0xb3, 0, 0}, + {0x4E, 0, 0, 0, 0}, + {0x4F, 0x2, 0x2, 0, 0}, + {0x50, 0, 0, 0, 0}, + {0x51, 0x9, 0x9, 0, 0}, + {0x52, 0x5, 0x5, 0, 0}, + {0x53, 0x17, 0x17, 0, 0}, + {0x54, 0x38, 0x38, 0, 0}, + {0x55, 0, 0, 0, 0}, + {0x56, 0, 0, 0, 0}, + {0x57, 0xb, 0xb, 0, 0}, + {0x58, 0, 0, 0, 0}, + {0x59, 0, 0, 0, 0}, + {0x5A, 0, 0, 0, 0}, + {0x5B, 0, 0, 0, 0}, + {0x5C, 0, 0, 0, 0}, + {0x5D, 0, 0, 0, 0}, + {0x5E, 0x88, 0x88, 0, 0}, + {0x5F, 0xcc, 0xcc, 0, 0}, + {0x60, 0x74, 0x74, 0, 0}, + {0x61, 0x74, 0x74, 0, 0}, + {0x62, 0x74, 0x74, 0, 0}, + {0x63, 0x44, 0x44, 0, 0}, + {0x64, 0x77, 0x77, 0, 0}, + {0x65, 0x44, 0x44, 0, 0}, + {0x66, 0x77, 0x77, 0, 0}, + {0x67, 0x55, 0x55, 0, 0}, + {0x68, 0x77, 0x77, 0, 0}, + {0x69, 0x77, 0x77, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0x7f, 0x7f, 0, 0}, + {0x6C, 0x8, 0x8, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0x88, 0x88, 0, 0}, + {0x6F, 0x66, 0x66, 0, 0}, + {0x70, 0x66, 0x66, 0, 0}, + {0x71, 0x28, 0x28, 0, 0}, + {0x72, 0x55, 0x55, 0, 0}, + {0x73, 0x4, 0x4, 0, 0}, + {0x74, 0, 0, 0, 0}, + {0x75, 0, 0, 0, 0}, + {0x76, 0, 0, 0, 0}, + {0x77, 0x1, 0x1, 0, 0}, + {0x78, 0xd6, 0xd6, 0, 0}, + {0x79, 0, 0, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0xb4, 0xb4, 0, 0}, + {0x84, 0x1, 0x1, 0, 0}, + {0x85, 0x20, 0x20, 0, 0}, + {0x86, 0x5, 0x5, 0, 0}, + {0x87, 0xff, 0xff, 0, 0}, + {0x88, 0x7, 0x7, 0, 0}, + {0x89, 0x77, 0x77, 0, 0}, + {0x8A, 0x77, 0x77, 0, 0}, + {0x8B, 0x77, 0x77, 0, 0}, + {0x8C, 0x77, 0x77, 0, 0}, + {0x8D, 0x8, 0x8, 0, 0}, + {0x8E, 0xa, 0xa, 0, 0}, + {0x8F, 0x8, 0x8, 0, 0}, + {0x90, 0x18, 0x18, 0, 0}, + {0x91, 0x5, 0x5, 0, 0}, + {0x92, 0x1f, 0x1f, 0, 0}, + {0x93, 0x10, 0x10, 0, 0}, + {0x94, 0x3, 0x3, 0, 0}, + {0x95, 0, 0, 0, 0}, + {0x96, 0, 0, 0, 0}, + {0x97, 0xaa, 0xaa, 0, 0}, + {0x98, 0, 0, 0, 0}, + {0x99, 0x23, 0x23, 0, 0}, + {0x9A, 0x7, 0x7, 0, 0}, + {0x9B, 0xf, 0xf, 0, 0}, + {0x9C, 0x10, 0x10, 0, 0}, + {0x9D, 0x3, 0x3, 0, 0}, + {0x9E, 0x4, 0x4, 0, 0}, + {0x9F, 0x20, 0x20, 0, 0}, + {0xA0, 0, 0, 0, 0}, + {0xA1, 0, 0, 0, 0}, + {0xA2, 0, 0, 0, 0}, + {0xA3, 0, 0, 0, 0}, + {0xA4, 0x1, 0x1, 0, 0}, + {0xA5, 0x77, 0x77, 0, 0}, + {0xA6, 0x77, 0x77, 0, 0}, + {0xA7, 0x77, 0x77, 0, 0}, + {0xA8, 0x77, 0x77, 0, 0}, + {0xA9, 0x8c, 0x8c, 0, 0}, + {0xAA, 0x88, 0x88, 0, 0}, + {0xAB, 0x78, 0x78, 0, 0}, + {0xAC, 0x57, 0x57, 0, 0}, + {0xAD, 0x88, 0x88, 0, 0}, + {0xAE, 0, 0, 0, 0}, + {0xAF, 0x8, 0x8, 0, 0}, + {0xB0, 0x88, 0x88, 0, 0}, + {0xB1, 0, 0, 0, 0}, + {0xB2, 0x1b, 0x1b, 0, 0}, + {0xB3, 0x3, 0x3, 0, 0}, + {0xB4, 0x24, 0x24, 0, 0}, + {0xB5, 0x3, 0x3, 0, 0}, + {0xB6, 0x1b, 0x1b, 0, 0}, + {0xB7, 0x24, 0x24, 0, 0}, + {0xB8, 0x3, 0x3, 0, 0}, + {0xB9, 0, 0, 0, 0}, + {0xBA, 0xaa, 0xaa, 0, 0}, + {0xBB, 0, 0, 0, 0}, + {0xBC, 0x4, 0x4, 0, 0}, + {0xBD, 0, 0, 0, 0}, + {0xBE, 0x8, 0x8, 0, 0}, + {0xBF, 0x11, 0x11, 0, 0}, + {0xC0, 0, 0, 0, 0}, + {0xC1, 0, 0, 0, 0}, + {0xC2, 0x62, 0x62, 0, 0}, + {0xC3, 0x1e, 0x1e, 0, 0}, + {0xC4, 0x33, 0x33, 0, 0}, + {0xC5, 0x37, 0x37, 0, 0}, + {0xC6, 0, 0, 0, 0}, + {0xC7, 0x70, 0x70, 0, 0}, + {0xC8, 0x1e, 0x1e, 0, 0}, + {0xC9, 0x6, 0x6, 0, 0}, + {0xCA, 0x4, 0x4, 0, 0}, + {0xCB, 0x2f, 0x2f, 0, 0}, + {0xCC, 0xf, 0xf, 0, 0}, + {0xCD, 0, 0, 0, 0}, + {0xCE, 0xff, 0xff, 0, 0}, + {0xCF, 0x8, 0x8, 0, 0}, + {0xD0, 0x3f, 0x3f, 0, 0}, + {0xD1, 0x3f, 0x3f, 0, 0}, + {0xD2, 0x3f, 0x3f, 0, 0}, + {0xD3, 0, 0, 0, 0}, + {0xD4, 0, 0, 0, 0}, + {0xD5, 0, 0, 0, 0}, + {0xD6, 0xcc, 0xcc, 0, 0}, + {0xD7, 0, 0, 0, 0}, + {0xD8, 0x8, 0x8, 0, 0}, + {0xD9, 0x8, 0x8, 0, 0}, + {0xDA, 0x8, 0x8, 0, 0}, + {0xDB, 0x11, 0x11, 0, 0}, + {0xDC, 0, 0, 0, 0}, + {0xDD, 0x87, 0x87, 0, 0}, + {0xDE, 0x88, 0x88, 0, 0}, + {0xDF, 0x8, 0x8, 0, 0}, + {0xE0, 0x8, 0x8, 0, 0}, + {0xE1, 0x8, 0x8, 0, 0}, + {0xE2, 0, 0, 0, 0}, + {0xE3, 0, 0, 0, 0}, + {0xE4, 0, 0, 0, 0}, + {0xE5, 0xf5, 0xf5, 0, 0}, + {0xE6, 0x30, 0x30, 0, 0}, + {0xE7, 0x1, 0x1, 0, 0}, + {0xE8, 0, 0, 0, 0}, + {0xE9, 0xff, 0xff, 0, 0}, + {0xEA, 0, 0, 0, 0}, + {0xEB, 0, 0, 0, 0}, + {0xEC, 0x22, 0x22, 0, 0}, + {0xED, 0, 0, 0, 0}, + {0xEE, 0, 0, 0, 0}, + {0xEF, 0, 0, 0, 0}, + {0xF0, 0x3, 0x3, 0, 0}, + {0xF1, 0x1, 0x1, 0, 0}, + {0xF2, 0, 0, 0, 0}, + {0xF3, 0, 0, 0, 0}, + {0xF4, 0, 0, 0, 0}, + {0xF5, 0, 0, 0, 0}, + {0xF6, 0, 0, 0, 0}, + {0xF7, 0x6, 0x6, 0, 0}, + {0xF8, 0, 0, 0, 0}, + {0xF9, 0, 0, 0, 0}, + {0xFA, 0x40, 0x40, 0, 0}, + {0xFB, 0, 0, 0, 0}, + {0xFC, 0x1, 0x1, 0, 0}, + {0xFD, 0x80, 0x80, 0, 0}, + {0xFE, 0x2, 0x2, 0, 0}, + {0xFF, 0x10, 0x10, 0, 0}, + {0x100, 0x2, 0x2, 0, 0}, + {0x101, 0x1e, 0x1e, 0, 0}, + {0x102, 0x1e, 0x1e, 0, 0}, + {0x103, 0, 0, 0, 0}, + {0x104, 0x1f, 0x1f, 0, 0}, + {0x105, 0, 0x8, 0, 1}, + {0x106, 0x2a, 0x2a, 0, 0}, + {0x107, 0xf, 0xf, 0, 0}, + {0x108, 0, 0, 0, 0}, + {0x109, 0, 0, 0, 0}, + {0x10A, 0, 0, 0, 0}, + {0x10B, 0, 0, 0, 0}, + {0x10C, 0, 0, 0, 0}, + {0x10D, 0, 0, 0, 0}, + {0x10E, 0, 0, 0, 0}, + {0x10F, 0, 0, 0, 0}, + {0x110, 0, 0, 0, 0}, + {0x111, 0, 0, 0, 0}, + {0x112, 0, 0, 0, 0}, + {0x113, 0, 0, 0, 0}, + {0x114, 0, 0, 0, 0}, + {0x115, 0, 0, 0, 0}, + {0x116, 0, 0, 0, 0}, + {0x117, 0, 0, 0, 0}, + {0x118, 0, 0, 0, 0}, + {0x119, 0, 0, 0, 0}, + {0x11A, 0, 0, 0, 0}, + {0x11B, 0, 0, 0, 0}, + {0x11C, 0x1, 0x1, 0, 0}, + {0x11D, 0, 0, 0, 0}, + {0x11E, 0, 0, 0, 0}, + {0x11F, 0, 0, 0, 0}, + {0x120, 0, 0, 0, 0}, + {0x121, 0, 0, 0, 0}, + {0x122, 0x80, 0x80, 0, 0}, + {0x123, 0, 0, 0, 0}, + {0x124, 0xf8, 0xf8, 0, 0}, + {0x125, 0, 0, 0, 0}, + {0x126, 0, 0, 0, 0}, + {0x127, 0, 0, 0, 0}, + {0x128, 0, 0, 0, 0}, + {0x129, 0, 0, 0, 0}, + {0x12A, 0, 0, 0, 0}, + {0x12B, 0, 0, 0, 0}, + {0x12C, 0, 0, 0, 0}, + {0x12D, 0, 0, 0, 0}, + {0x12E, 0, 0, 0, 0}, + {0x12F, 0, 0, 0, 0}, + {0x130, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +#define LCNPHY_NUM_DIG_FILT_COEFFS 16 +#define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13 + +static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK] + [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = { + {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64, + 128, 64,}, + {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93, + 167, 93,}, + {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64, + 128, 64,}, + {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760, + 170, 340, 170,}, + {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760, + 256, 185, 256,}, + {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760, + 256, 273, 256,}, + {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760, + 256, 352, 256,}, + {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760, + 128, 233, 128,}, + {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256, + 1881, 256,}, + {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256, + 1881, 256,}, + {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128, + 384, 288,}, + {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864, + 128, 384, 288,}, + {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760, + 170, 340, 170,}, +}; + +#define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3 +static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM] + [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = { + {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0, + 0x278, 0xfea0, 0x80, 0x100, 0x80,}, + {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, + 750, 0xFE2B, 212, 0xFFCE, 212,}, + {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748, + 0xFEF2, 128, 0xFFE2, 128} +}; + +#define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \ + mod_phy_reg(pi, 0x4a4, \ + (0x1ff << 0), \ + (u16)(idx) << 0) + +#define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \ + mod_phy_reg(pi, 0x4a5, \ + (0x7 << 8), \ + (u16)(npt) << 8) + +#define wlc_lcnphy_get_tx_pwr_ctrl(pi) \ + (read_phy_reg((pi), 0x4a4) & \ + ((0x1 << 15) | \ + (0x1 << 14) | \ + (0x1 << 13))) + +#define wlc_lcnphy_get_tx_pwr_npt(pi) \ + ((read_phy_reg(pi, 0x4a5) & \ + (0x7 << 8)) >> \ + 8) + +#define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \ + (read_phy_reg(pi, 0x473) & 0x1ff) + +#define wlc_lcnphy_get_target_tx_pwr(pi) \ + ((read_phy_reg(pi, 0x4a7) & \ + (0xff << 0)) >> \ + 0) + +#define wlc_lcnphy_set_target_tx_pwr(pi, target) \ + mod_phy_reg(pi, 0x4a7, \ + (0xff << 0), \ + (u16)(target) << 0) + +#define wlc_radio_2064_rcal_done(pi) \ + (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20)) + +#define tempsense_done(pi) \ + (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000)) + +#define LCNPHY_IQLOCC_READ(val) \ + ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f))) + +#define FIXED_TXPWR 78 +#define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val)) + +void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti) +{ + wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456); +} + +void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti) +{ + wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456); +} + +static void +wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id, + const u16 *tbl_ptr, u32 tbl_len, + u32 tbl_width, u32 tbl_offset) +{ + struct phytbl_info tab; + tab.tbl_id = tbl_id; + tab.tbl_ptr = tbl_ptr; + tab.tbl_len = tbl_len; + tab.tbl_width = tbl_width; + tab.tbl_offset = tbl_offset; + wlc_lcnphy_read_table(pi, &tab); +} + +static void +wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id, + const u16 *tbl_ptr, u32 tbl_len, + u32 tbl_width, u32 tbl_offset) +{ + + struct phytbl_info tab; + tab.tbl_id = tbl_id; + tab.tbl_ptr = tbl_ptr; + tab.tbl_len = tbl_len; + tab.tbl_width = tbl_width; + tab.tbl_offset = tbl_offset; + wlc_lcnphy_write_table(pi, &tab); +} + +static u32 +wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) +{ + u32 quotient, remainder, roundup, rbit; + + quotient = dividend / divisor; + remainder = dividend % divisor; + rbit = divisor & 1; + roundup = (divisor >> 1) + rbit; + + while (precision--) { + quotient <<= 1; + if (remainder >= roundup) { + quotient++; + remainder = ((remainder - roundup) << 1) + rbit; + } else { + remainder <<= 1; + } + } + + if (remainder >= roundup) + quotient++; + + return quotient; +} + +static int wlc_lcnphy_calc_floor(s16 coeff_x, int type) +{ + int k; + k = 0; + if (type == 0) { + if (coeff_x < 0) + k = (coeff_x - 1) / 2; + else + k = coeff_x / 2; + } + + if (type == 1) { + if ((coeff_x + 1) < 0) + k = (coeff_x) / 2; + else + k = (coeff_x + 1) / 2; + } + return k; +} + +static void +wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains) +{ + u16 dac_gain, rfgain0, rfgain1; + + dac_gain = read_phy_reg(pi, 0x439) >> 0; + gains->dac_gain = (dac_gain & 0x380) >> 7; + + rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0; + rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0; + + gains->gm_gain = rfgain0 & 0xff; + gains->pga_gain = (rfgain0 >> 8) & 0xff; + gains->pad_gain = rfgain1 & 0xff; +} + + +static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain) +{ + u16 dac_ctrl; + + dac_ctrl = (read_phy_reg(pi, 0x439) >> 0); + dac_ctrl = dac_ctrl & 0xc7f; + dac_ctrl = dac_ctrl | (dac_gain << 7); + mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0); + +} + +static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable) +{ + u16 bit = bEnable ? 1 : 0; + + mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7); + + mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14); + + mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6); +} + +static void +wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable) +{ + u16 ebit = enable ? 1 : 0; + + mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8); + + mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0); + + if (LCNREV_LT(pi->pubpi.phy_rev, 2)) { + mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4); + mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6); + mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5); + mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6); + } else { + mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12); + mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13); + mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5); + } + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10); + mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3); + } +} + +static void +wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi, + u16 trsw, + u16 ext_lna, + u16 biq2, + u16 biq1, + u16 tia, u16 lna2, u16 lna1) +{ + u16 gain0_15, gain16_19; + + gain16_19 = biq2 & 0xf; + gain0_15 = ((biq1 & 0xf) << 12) | + ((tia & 0xf) << 8) | + ((lna2 & 0x3) << 6) | + ((lna2 & 0x3) << 4) | + ((lna1 & 0x3) << 2) | + ((lna1 & 0x3) << 0); + + mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0); + mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); + mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); + + if (LCNREV_LT(pi->pubpi.phy_rev, 2)) { + mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9); + mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10); + } else { + mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10); + + mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15); + + mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9); + } + + mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0); + +} + +static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx) +{ + + mod_phy_reg(pi, 0x44d, + (0x1 << 1) | + (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0)); + + or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0)); +} + +static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi) +{ + + and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0))); +} + +static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b) +{ + mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0); + + mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0); + + mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0); + + mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0); + + mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0); + + mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0); + +} + +static bool +wlc_lcnphy_rx_iq_est(struct brcms_phy *pi, + u16 num_samps, + u8 wait_time, struct lcnphy_iq_est *iq_est) +{ + int wait_count = 0; + bool result = true; + u8 phybw40; + phybw40 = CHSPEC_IS40(pi->radio_chanspec); + + mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5); + + mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3); + + mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0); + + mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0); + + mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8); + + mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9); + + while (read_phy_reg(pi, 0x481) & (0x1 << 9)) { + + if (wait_count > (10 * 500)) { + result = false; + goto cleanup; + } + udelay(100); + wait_count++; + } + + iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) | + (u32) read_phy_reg(pi, 0x484); + iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) | + (u32) read_phy_reg(pi, 0x486); + iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) | + (u32) read_phy_reg(pi, 0x488); + +cleanup: + mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3); + + mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5); + + return result; +} + +static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps) +{ +#define LCNPHY_MIN_RXIQ_PWR 2 + bool result; + u16 a0_new, b0_new; + struct lcnphy_iq_est iq_est = { 0, 0, 0 }; + s32 a, b, temp; + s16 iq_nbits, qq_nbits, arsh, brsh; + s32 iq; + u32 ii, qq; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0); + b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0); + mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2); + + mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6); + + wlc_lcnphy_set_rx_iq_comp(pi, 0, 0); + + result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est); + if (!result) + goto cleanup; + + iq = (s32) iq_est.iq_prod; + ii = iq_est.i_pwr; + qq = iq_est.q_pwr; + + if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) { + result = false; + |