Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /*
0003  * Copyright (c) 2010 Broadcom Corporation
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/delay.h>
0008 #include <linux/cordic.h>
0009 
0010 #include <pmu.h>
0011 #include <d11.h>
0012 #include <phy_shim.h>
0013 #include "phy_qmath.h"
0014 #include "phy_hal.h"
0015 #include "phy_radio.h"
0016 #include "phytbl_lcn.h"
0017 #include "phy_lcn.h"
0018 
0019 #define PLL_2064_NDIV       90
0020 #define PLL_2064_LOW_END_VCO    3000
0021 #define PLL_2064_LOW_END_KVCO   27
0022 #define PLL_2064_HIGH_END_VCO   4200
0023 #define PLL_2064_HIGH_END_KVCO  68
0024 #define PLL_2064_LOOP_BW_DOUBLER    200
0025 #define PLL_2064_D30_DOUBLER        10500
0026 #define PLL_2064_LOOP_BW    260
0027 #define PLL_2064_D30        8000
0028 #define PLL_2064_CAL_REF_TO 8
0029 #define PLL_2064_MHZ        1000000
0030 #define PLL_2064_OPEN_LOOP_DELAY    5
0031 
0032 #define TEMPSENSE           1
0033 #define VBATSENSE           2
0034 
0035 #define NOISE_IF_UPD_CHK_INTERVAL   1
0036 #define NOISE_IF_UPD_RST_INTERVAL   60
0037 #define NOISE_IF_UPD_THRESHOLD_CNT  1
0038 #define NOISE_IF_UPD_TRHRESHOLD 50
0039 #define NOISE_IF_UPD_TIMEOUT        1000
0040 #define NOISE_IF_OFF            0
0041 #define NOISE_IF_CHK            1
0042 #define NOISE_IF_ON         2
0043 
0044 #define PAPD_BLANKING_PROFILE       3
0045 #define PAPD2LUT            0
0046 #define PAPD_CORR_NORM          0
0047 #define PAPD_BLANKING_THRESHOLD     0
0048 #define PAPD_STOP_AFTER_LAST_UPDATE 0
0049 
0050 #define LCN_TARGET_PWR  60
0051 
0052 #define LCN_VBAT_OFFSET_433X 34649679
0053 #define LCN_VBAT_SLOPE_433X  8258032
0054 
0055 #define LCN_VBAT_SCALE_NOM  53
0056 #define LCN_VBAT_SCALE_DEN  432
0057 
0058 #define LCN_TEMPSENSE_OFFSET  80812
0059 #define LCN_TEMPSENSE_DEN  2647
0060 
0061 #define LCN_BW_LMT  200
0062 #define LCN_CUR_LMT 1250
0063 #define LCN_MULT    1
0064 #define LCN_VCO_DIV 30
0065 #define LCN_OFFSET  680
0066 #define LCN_FACT    490
0067 #define LCN_CUR_DIV 2640
0068 
0069 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
0070     (0 + 8)
0071 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
0072     (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)
0073 
0074 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \
0075     (0 + 8)
0076 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \
0077     (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)
0078 
0079 #define wlc_lcnphy_enable_tx_gain_override(pi) \
0080     wlc_lcnphy_set_tx_gain_override(pi, true)
0081 #define wlc_lcnphy_disable_tx_gain_override(pi) \
0082     wlc_lcnphy_set_tx_gain_override(pi, false)
0083 
0084 #define wlc_lcnphy_iqcal_active(pi) \
0085     (read_phy_reg((pi), 0x451) & \
0086      ((0x1 << 15) | (0x1 << 14)))
0087 
0088 #define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
0089 #define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
0090     (pi->temppwrctrl_capable)
0091 #define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
0092     (pi->hwpwrctrl_capable)
0093 
0094 #define SWCTRL_BT_TX        0x18
0095 #define SWCTRL_OVR_DISABLE  0x40
0096 
0097 #define AFE_CLK_INIT_MODE_TXRX2X    1
0098 #define AFE_CLK_INIT_MODE_PAPD      0
0099 
0100 #define LCNPHY_TBL_ID_IQLOCAL           0x00
0101 
0102 #define LCNPHY_TBL_ID_RFSEQ         0x08
0103 #define LCNPHY_TBL_ID_GAIN_IDX      0x0d
0104 #define LCNPHY_TBL_ID_SW_CTRL           0x0f
0105 #define LCNPHY_TBL_ID_GAIN_TBL      0x12
0106 #define LCNPHY_TBL_ID_SPUR          0x14
0107 #define LCNPHY_TBL_ID_SAMPLEPLAY        0x15
0108 #define LCNPHY_TBL_ID_SAMPLEPLAY1       0x16
0109 
0110 #define LCNPHY_TX_PWR_CTRL_RATE_OFFSET  832
0111 #define LCNPHY_TX_PWR_CTRL_MAC_OFFSET   128
0112 #define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET  192
0113 #define LCNPHY_TX_PWR_CTRL_IQ_OFFSET        320
0114 #define LCNPHY_TX_PWR_CTRL_LO_OFFSET        448
0115 #define LCNPHY_TX_PWR_CTRL_PWR_OFFSET       576
0116 
0117 #define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313  140
0118 
0119 #define LCNPHY_TX_PWR_CTRL_START_NPT        1
0120 #define LCNPHY_TX_PWR_CTRL_MAX_NPT          7
0121 
0122 #define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
0123 
0124 #define LCNPHY_ACI_DETECT_START      1
0125 #define LCNPHY_ACI_DETECT_PROGRESS   2
0126 #define LCNPHY_ACI_DETECT_STOP       3
0127 
0128 #define LCNPHY_ACI_CRSHIFRMLO_TRSH 100
0129 #define LCNPHY_ACI_GLITCH_TRSH 2000
0130 #define LCNPHY_ACI_TMOUT 250
0131 #define LCNPHY_ACI_DETECT_TIMEOUT  2
0132 #define LCNPHY_ACI_START_DELAY 0
0133 
0134 #define wlc_lcnphy_tx_gain_override_enabled(pi) \
0135     (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
0136 
0137 #define wlc_lcnphy_total_tx_frames(pi) \
0138     wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \
0139                 offsetof(struct macstat, txallfrm))
0140 
0141 struct lcnphy_txgains {
0142     u16 gm_gain;
0143     u16 pga_gain;
0144     u16 pad_gain;
0145     u16 dac_gain;
0146 };
0147 
0148 enum lcnphy_cal_mode {
0149     LCNPHY_CAL_FULL,
0150     LCNPHY_CAL_RECAL,
0151     LCNPHY_CAL_CURRECAL,
0152     LCNPHY_CAL_DIGCAL,
0153     LCNPHY_CAL_GCTRL
0154 };
0155 
0156 struct lcnphy_rx_iqcomp {
0157     u8 chan;
0158     s16 a;
0159     s16 b;
0160 };
0161 
0162 struct lcnphy_spb_tone {
0163     s16 re;
0164     s16 im;
0165 };
0166 
0167 struct lcnphy_unsign16_struct {
0168     u16 re;
0169     u16 im;
0170 };
0171 
0172 struct lcnphy_iq_est {
0173     u32 iq_prod;
0174     u32 i_pwr;
0175     u32 q_pwr;
0176 };
0177 
0178 struct lcnphy_sfo_cfg {
0179     u16 ptcentreTs20;
0180     u16 ptcentreFactor;
0181 };
0182 
0183 enum lcnphy_papd_cal_type {
0184     LCNPHY_PAPD_CAL_CW,
0185     LCNPHY_PAPD_CAL_OFDM
0186 };
0187 
0188 typedef u16 iqcal_gain_params_lcnphy[9];
0189 
0190 static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
0191     {0, 0, 0, 0, 0, 0, 0, 0, 0},
0192 };
0193 
0194 static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
0195     tbl_iqcal_gainparams_lcnphy_2G,
0196 };
0197 
0198 static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
0199     ARRAY_SIZE(tbl_iqcal_gainparams_lcnphy_2G),
0200 };
0201 
0202 static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = {
0203     {965, 1087},
0204     {967, 1085},
0205     {969, 1082},
0206     {971, 1080},
0207     {973, 1078},
0208     {975, 1076},
0209     {977, 1073},
0210     {979, 1071},
0211     {981, 1069},
0212     {983, 1067},
0213     {985, 1065},
0214     {987, 1063},
0215     {989, 1060},
0216     {994, 1055}
0217 };
0218 
0219 static const
0220 u16 lcnphy_iqcal_loft_gainladder[] = {
0221     ((2 << 8) | 0),
0222     ((3 << 8) | 0),
0223     ((4 << 8) | 0),
0224     ((6 << 8) | 0),
0225     ((8 << 8) | 0),
0226     ((11 << 8) | 0),
0227     ((16 << 8) | 0),
0228     ((16 << 8) | 1),
0229     ((16 << 8) | 2),
0230     ((16 << 8) | 3),
0231     ((16 << 8) | 4),
0232     ((16 << 8) | 5),
0233     ((16 << 8) | 6),
0234     ((16 << 8) | 7),
0235     ((23 << 8) | 7),
0236     ((32 << 8) | 7),
0237     ((45 << 8) | 7),
0238     ((64 << 8) | 7),
0239     ((91 << 8) | 7),
0240     ((128 << 8) | 7)
0241 };
0242 
0243 static const
0244 u16 lcnphy_iqcal_ir_gainladder[] = {
0245     ((1 << 8) | 0),
0246     ((2 << 8) | 0),
0247     ((4 << 8) | 0),
0248     ((6 << 8) | 0),
0249     ((8 << 8) | 0),
0250     ((11 << 8) | 0),
0251     ((16 << 8) | 0),
0252     ((23 << 8) | 0),
0253     ((32 << 8) | 0),
0254     ((45 << 8) | 0),
0255     ((64 << 8) | 0),
0256     ((64 << 8) | 1),
0257     ((64 << 8) | 2),
0258     ((64 << 8) | 3),
0259     ((64 << 8) | 4),
0260     ((64 << 8) | 5),
0261     ((64 << 8) | 6),
0262     ((64 << 8) | 7),
0263     ((91 << 8) | 7),
0264     ((128 << 8) | 7)
0265 };
0266 
0267 static const
0268 struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = {
0269     {88, 0},
0270     {73, 49},
0271     {34, 81},
0272     {-17, 86},
0273     {-62, 62},
0274     {-86, 17},
0275     {-81, -34},
0276     {-49, -73},
0277     {0, -88},
0278     {49, -73},
0279     {81, -34},
0280     {86, 17},
0281     {62, 62},
0282     {17, 86},
0283     {-34, 81},
0284     {-73, 49},
0285     {-88, 0},
0286     {-73, -49},
0287     {-34, -81},
0288     {17, -86},
0289     {62, -62},
0290     {86, -17},
0291     {81, 34},
0292     {49, 73},
0293     {0, 88},
0294     {-49, 73},
0295     {-81, 34},
0296     {-86, -17},
0297     {-62, -62},
0298     {-17, -86},
0299     {34, -81},
0300     {73, -49},
0301 };
0302 
0303 static const
0304 u16 iqlo_loopback_rf_regs[20] = {
0305     RADIO_2064_REG036,
0306     RADIO_2064_REG11A,
0307     RADIO_2064_REG03A,
0308     RADIO_2064_REG025,
0309     RADIO_2064_REG028,
0310     RADIO_2064_REG005,
0311     RADIO_2064_REG112,
0312     RADIO_2064_REG0FF,
0313     RADIO_2064_REG11F,
0314     RADIO_2064_REG00B,
0315     RADIO_2064_REG113,
0316     RADIO_2064_REG007,
0317     RADIO_2064_REG0FC,
0318     RADIO_2064_REG0FD,
0319     RADIO_2064_REG012,
0320     RADIO_2064_REG057,
0321     RADIO_2064_REG059,
0322     RADIO_2064_REG05C,
0323     RADIO_2064_REG078,
0324     RADIO_2064_REG092,
0325 };
0326 
0327 static const
0328 u16 tempsense_phy_regs[14] = {
0329     0x503,
0330     0x4a4,
0331     0x4d0,
0332     0x4d9,
0333     0x4da,
0334     0x4a6,
0335     0x938,
0336     0x939,
0337     0x4d8,
0338     0x4d0,
0339     0x4d7,
0340     0x4a5,
0341     0x40d,
0342     0x4a2,
0343 };
0344 
0345 static const
0346 u16 rxiq_cal_rf_reg[11] = {
0347     RADIO_2064_REG098,
0348     RADIO_2064_REG116,
0349     RADIO_2064_REG12C,
0350     RADIO_2064_REG06A,
0351     RADIO_2064_REG00B,
0352     RADIO_2064_REG01B,
0353     RADIO_2064_REG113,
0354     RADIO_2064_REG01D,
0355     RADIO_2064_REG114,
0356     RADIO_2064_REG02E,
0357     RADIO_2064_REG12A,
0358 };
0359 
0360 static const u32 lcnphy_23bitgaincode_table[] = {
0361     0x200100,
0362     0x200200,
0363     0x200004,
0364     0x200014,
0365     0x200024,
0366     0x200034,
0367     0x200134,
0368     0x200234,
0369     0x200334,
0370     0x200434,
0371     0x200037,
0372     0x200137,
0373     0x200237,
0374     0x200337,
0375     0x200437,
0376     0x000035,
0377     0x000135,
0378     0x000235,
0379     0x000037,
0380     0x000137,
0381     0x000237,
0382     0x000337,
0383     0x00013f,
0384     0x00023f,
0385     0x00033f,
0386     0x00034f,
0387     0x00044f,
0388     0x00144f,
0389     0x00244f,
0390     0x00254f,
0391     0x00354f,
0392     0x00454f,
0393     0x00464f,
0394     0x01464f,
0395     0x02464f,
0396     0x03464f,
0397     0x04464f,
0398 };
0399 
0400 static const s8 lcnphy_gain_table[] = {
0401     -16,
0402     -13,
0403     10,
0404     7,
0405     4,
0406     0,
0407     3,
0408     6,
0409     9,
0410     12,
0411     15,
0412     18,
0413     21,
0414     24,
0415     27,
0416     30,
0417     33,
0418     36,
0419     39,
0420     42,
0421     45,
0422     48,
0423     50,
0424     53,
0425     56,
0426     59,
0427     62,
0428     65,
0429     68,
0430     71,
0431     74,
0432     77,
0433     80,
0434     83,
0435     86,
0436     89,
0437     92,
0438 };
0439 
0440 static const s8 lcnphy_gain_index_offset_for_rssi[] = {
0441     7,
0442     7,
0443     7,
0444     7,
0445     7,
0446     7,
0447     7,
0448     8,
0449     7,
0450     7,
0451     6,
0452     7,
0453     7,
0454     4,
0455     4,
0456     4,
0457     4,
0458     4,
0459     4,
0460     4,
0461     4,
0462     3,
0463     3,
0464     3,
0465     3,
0466     3,
0467     3,
0468     4,
0469     2,
0470     2,
0471     2,
0472     2,
0473     2,
0474     2,
0475     -1,
0476     -2,
0477     -2,
0478     -2
0479 };
0480 
0481 struct chan_info_2064_lcnphy {
0482     uint chan;
0483     uint freq;
0484     u8 logen_buftune;
0485     u8 logen_rccr_tx;
0486     u8 txrf_mix_tune_ctrl;
0487     u8 pa_input_tune_g;
0488     u8 logen_rccr_rx;
0489     u8 pa_rxrf_lna1_freq_tune;
0490     u8 pa_rxrf_lna2_freq_tune;
0491     u8 rxrf_rxrf_spare1;
0492 };
0493 
0494 static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {
0495     {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0496     {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0497     {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0498     {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0499     {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0500     {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0501     {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0502     {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0503     {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0504     {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0505     {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0506     {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0507     {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0508     {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
0509 };
0510 
0511 static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {
0512     {0x00, 0, 0, 0, 0},
0513     {0x01, 0x64, 0x64, 0, 0},
0514     {0x02, 0x20, 0x20, 0, 0},
0515     {0x03, 0x66, 0x66, 0, 0},
0516     {0x04, 0xf8, 0xf8, 0, 0},
0517     {0x05, 0, 0, 0, 0},
0518     {0x06, 0x10, 0x10, 0, 0},
0519     {0x07, 0, 0, 0, 0},
0520     {0x08, 0, 0, 0, 0},
0521     {0x09, 0, 0, 0, 0},
0522     {0x0A, 0x37, 0x37, 0, 0},
0523     {0x0B, 0x6, 0x6, 0, 0},
0524     {0x0C, 0x55, 0x55, 0, 0},
0525     {0x0D, 0x8b, 0x8b, 0, 0},
0526     {0x0E, 0, 0, 0, 0},
0527     {0x0F, 0x5, 0x5, 0, 0},
0528     {0x10, 0, 0, 0, 0},
0529     {0x11, 0xe, 0xe, 0, 0},
0530     {0x12, 0, 0, 0, 0},
0531     {0x13, 0xb, 0xb, 0, 0},
0532     {0x14, 0x2, 0x2, 0, 0},
0533     {0x15, 0x12, 0x12, 0, 0},
0534     {0x16, 0x12, 0x12, 0, 0},
0535     {0x17, 0xc, 0xc, 0, 0},
0536     {0x18, 0xc, 0xc, 0, 0},
0537     {0x19, 0xc, 0xc, 0, 0},
0538     {0x1A, 0x8, 0x8, 0, 0},
0539     {0x1B, 0x2, 0x2, 0, 0},
0540     {0x1C, 0, 0, 0, 0},
0541     {0x1D, 0x1, 0x1, 0, 0},
0542     {0x1E, 0x12, 0x12, 0, 0},
0543     {0x1F, 0x6e, 0x6e, 0, 0},
0544     {0x20, 0x2, 0x2, 0, 0},
0545     {0x21, 0x23, 0x23, 0, 0},
0546     {0x22, 0x8, 0x8, 0, 0},
0547     {0x23, 0, 0, 0, 0},
0548     {0x24, 0, 0, 0, 0},
0549     {0x25, 0xc, 0xc, 0, 0},
0550     {0x26, 0x33, 0x33, 0, 0},
0551     {0x27, 0x55, 0x55, 0, 0},
0552     {0x28, 0, 0, 0, 0},
0553     {0x29, 0x30, 0x30, 0, 0},
0554     {0x2A, 0xb, 0xb, 0, 0},
0555     {0x2B, 0x1b, 0x1b, 0, 0},
0556     {0x2C, 0x3, 0x3, 0, 0},
0557     {0x2D, 0x1b, 0x1b, 0, 0},
0558     {0x2E, 0, 0, 0, 0},
0559     {0x2F, 0x20, 0x20, 0, 0},
0560     {0x30, 0xa, 0xa, 0, 0},
0561     {0x31, 0, 0, 0, 0},
0562     {0x32, 0x62, 0x62, 0, 0},
0563     {0x33, 0x19, 0x19, 0, 0},
0564     {0x34, 0x33, 0x33, 0, 0},
0565     {0x35, 0x77, 0x77, 0, 0},
0566     {0x36, 0, 0, 0, 0},
0567     {0x37, 0x70, 0x70, 0, 0},
0568     {0x38, 0x3, 0x3, 0, 0},
0569     {0x39, 0xf, 0xf, 0, 0},
0570     {0x3A, 0x6, 0x6, 0, 0},
0571     {0x3B, 0xcf, 0xcf, 0, 0},
0572     {0x3C, 0x1a, 0x1a, 0, 0},
0573     {0x3D, 0x6, 0x6, 0, 0},
0574     {0x3E, 0x42, 0x42, 0, 0},
0575     {0x3F, 0, 0, 0, 0},
0576     {0x40, 0xfb, 0xfb, 0, 0},
0577     {0x41, 0x9a, 0x9a, 0, 0},
0578     {0x42, 0x7a, 0x7a, 0, 0},
0579     {0x43, 0x29, 0x29, 0, 0},
0580     {0x44, 0, 0, 0, 0},
0581     {0x45, 0x8, 0x8, 0, 0},
0582     {0x46, 0xce, 0xce, 0, 0},
0583     {0x47, 0x27, 0x27, 0, 0},
0584     {0x48, 0x62, 0x62, 0, 0},
0585     {0x49, 0x6, 0x6, 0, 0},
0586     {0x4A, 0x58, 0x58, 0, 0},
0587     {0x4B, 0xf7, 0xf7, 0, 0},
0588     {0x4C, 0, 0, 0, 0},
0589     {0x4D, 0xb3, 0xb3, 0, 0},
0590     {0x4E, 0, 0, 0, 0},
0591     {0x4F, 0x2, 0x2, 0, 0},
0592     {0x50, 0, 0, 0, 0},
0593     {0x51, 0x9, 0x9, 0, 0},
0594     {0x52, 0x5, 0x5, 0, 0},
0595     {0x53, 0x17, 0x17, 0, 0},
0596     {0x54, 0x38, 0x38, 0, 0},
0597     {0x55, 0, 0, 0, 0},
0598     {0x56, 0, 0, 0, 0},
0599     {0x57, 0xb, 0xb, 0, 0},
0600     {0x58, 0, 0, 0, 0},
0601     {0x59, 0, 0, 0, 0},
0602     {0x5A, 0, 0, 0, 0},
0603     {0x5B, 0, 0, 0, 0},
0604     {0x5C, 0, 0, 0, 0},
0605     {0x5D, 0, 0, 0, 0},
0606     {0x5E, 0x88, 0x88, 0, 0},
0607     {0x5F, 0xcc, 0xcc, 0, 0},
0608     {0x60, 0x74, 0x74, 0, 0},
0609     {0x61, 0x74, 0x74, 0, 0},
0610     {0x62, 0x74, 0x74, 0, 0},
0611     {0x63, 0x44, 0x44, 0, 0},
0612     {0x64, 0x77, 0x77, 0, 0},
0613     {0x65, 0x44, 0x44, 0, 0},
0614     {0x66, 0x77, 0x77, 0, 0},
0615     {0x67, 0x55, 0x55, 0, 0},
0616     {0x68, 0x77, 0x77, 0, 0},
0617     {0x69, 0x77, 0x77, 0, 0},
0618     {0x6A, 0, 0, 0, 0},
0619     {0x6B, 0x7f, 0x7f, 0, 0},
0620     {0x6C, 0x8, 0x8, 0, 0},
0621     {0x6D, 0, 0, 0, 0},
0622     {0x6E, 0x88, 0x88, 0, 0},
0623     {0x6F, 0x66, 0x66, 0, 0},
0624     {0x70, 0x66, 0x66, 0, 0},
0625     {0x71, 0x28, 0x28, 0, 0},
0626     {0x72, 0x55, 0x55, 0, 0},
0627     {0x73, 0x4, 0x4, 0, 0},
0628     {0x74, 0, 0, 0, 0},
0629     {0x75, 0, 0, 0, 0},
0630     {0x76, 0, 0, 0, 0},
0631     {0x77, 0x1, 0x1, 0, 0},
0632     {0x78, 0xd6, 0xd6, 0, 0},
0633     {0x79, 0, 0, 0, 0},
0634     {0x7A, 0, 0, 0, 0},
0635     {0x7B, 0, 0, 0, 0},
0636     {0x7C, 0, 0, 0, 0},
0637     {0x7D, 0, 0, 0, 0},
0638     {0x7E, 0, 0, 0, 0},
0639     {0x7F, 0, 0, 0, 0},
0640     {0x80, 0, 0, 0, 0},
0641     {0x81, 0, 0, 0, 0},
0642     {0x82, 0, 0, 0, 0},
0643     {0x83, 0xb4, 0xb4, 0, 0},
0644     {0x84, 0x1, 0x1, 0, 0},
0645     {0x85, 0x20, 0x20, 0, 0},
0646     {0x86, 0x5, 0x5, 0, 0},
0647     {0x87, 0xff, 0xff, 0, 0},
0648     {0x88, 0x7, 0x7, 0, 0},
0649     {0x89, 0x77, 0x77, 0, 0},
0650     {0x8A, 0x77, 0x77, 0, 0},
0651     {0x8B, 0x77, 0x77, 0, 0},
0652     {0x8C, 0x77, 0x77, 0, 0},
0653     {0x8D, 0x8, 0x8, 0, 0},
0654     {0x8E, 0xa, 0xa, 0, 0},
0655     {0x8F, 0x8, 0x8, 0, 0},
0656     {0x90, 0x18, 0x18, 0, 0},
0657     {0x91, 0x5, 0x5, 0, 0},
0658     {0x92, 0x1f, 0x1f, 0, 0},
0659     {0x93, 0x10, 0x10, 0, 0},
0660     {0x94, 0x3, 0x3, 0, 0},
0661     {0x95, 0, 0, 0, 0},
0662     {0x96, 0, 0, 0, 0},
0663     {0x97, 0xaa, 0xaa, 0, 0},
0664     {0x98, 0, 0, 0, 0},
0665     {0x99, 0x23, 0x23, 0, 0},
0666     {0x9A, 0x7, 0x7, 0, 0},
0667     {0x9B, 0xf, 0xf, 0, 0},
0668     {0x9C, 0x10, 0x10, 0, 0},
0669     {0x9D, 0x3, 0x3, 0, 0},
0670     {0x9E, 0x4, 0x4, 0, 0},
0671     {0x9F, 0x20, 0x20, 0, 0},
0672     {0xA0, 0, 0, 0, 0},
0673     {0xA1, 0, 0, 0, 0},
0674     {0xA2, 0, 0, 0, 0},
0675     {0xA3, 0, 0, 0, 0},
0676     {0xA4, 0x1, 0x1, 0, 0},
0677     {0xA5, 0x77, 0x77, 0, 0},
0678     {0xA6, 0x77, 0x77, 0, 0},
0679     {0xA7, 0x77, 0x77, 0, 0},
0680     {0xA8, 0x77, 0x77, 0, 0},
0681     {0xA9, 0x8c, 0x8c, 0, 0},
0682     {0xAA, 0x88, 0x88, 0, 0},
0683     {0xAB, 0x78, 0x78, 0, 0},
0684     {0xAC, 0x57, 0x57, 0, 0},
0685     {0xAD, 0x88, 0x88, 0, 0},
0686     {0xAE, 0, 0, 0, 0},
0687     {0xAF, 0x8, 0x8, 0, 0},
0688     {0xB0, 0x88, 0x88, 0, 0},
0689     {0xB1, 0, 0, 0, 0},
0690     {0xB2, 0x1b, 0x1b, 0, 0},
0691     {0xB3, 0x3, 0x3, 0, 0},
0692     {0xB4, 0x24, 0x24, 0, 0},
0693     {0xB5, 0x3, 0x3, 0, 0},
0694     {0xB6, 0x1b, 0x1b, 0, 0},
0695     {0xB7, 0x24, 0x24, 0, 0},
0696     {0xB8, 0x3, 0x3, 0, 0},
0697     {0xB9, 0, 0, 0, 0},
0698     {0xBA, 0xaa, 0xaa, 0, 0},
0699     {0xBB, 0, 0, 0, 0},
0700     {0xBC, 0x4, 0x4, 0, 0},
0701     {0xBD, 0, 0, 0, 0},
0702     {0xBE, 0x8, 0x8, 0, 0},
0703     {0xBF, 0x11, 0x11, 0, 0},
0704     {0xC0, 0, 0, 0, 0},
0705     {0xC1, 0, 0, 0, 0},
0706     {0xC2, 0x62, 0x62, 0, 0},
0707     {0xC3, 0x1e, 0x1e, 0, 0},
0708     {0xC4, 0x33, 0x33, 0, 0},
0709     {0xC5, 0x37, 0x37, 0, 0},
0710     {0xC6, 0, 0, 0, 0},
0711     {0xC7, 0x70, 0x70, 0, 0},
0712     {0xC8, 0x1e, 0x1e, 0, 0},
0713     {0xC9, 0x6, 0x6, 0, 0},
0714     {0xCA, 0x4, 0x4, 0, 0},
0715     {0xCB, 0x2f, 0x2f, 0, 0},
0716     {0xCC, 0xf, 0xf, 0, 0},
0717     {0xCD, 0, 0, 0, 0},
0718     {0xCE, 0xff, 0xff, 0, 0},
0719     {0xCF, 0x8, 0x8, 0, 0},
0720     {0xD0, 0x3f, 0x3f, 0, 0},
0721     {0xD1, 0x3f, 0x3f, 0, 0},
0722     {0xD2, 0x3f, 0x3f, 0, 0},
0723     {0xD3, 0, 0, 0, 0},
0724     {0xD4, 0, 0, 0, 0},
0725     {0xD5, 0, 0, 0, 0},
0726     {0xD6, 0xcc, 0xcc, 0, 0},
0727     {0xD7, 0, 0, 0, 0},
0728     {0xD8, 0x8, 0x8, 0, 0},
0729     {0xD9, 0x8, 0x8, 0, 0},
0730     {0xDA, 0x8, 0x8, 0, 0},
0731     {0xDB, 0x11, 0x11, 0, 0},
0732     {0xDC, 0, 0, 0, 0},
0733     {0xDD, 0x87, 0x87, 0, 0},
0734     {0xDE, 0x88, 0x88, 0, 0},
0735     {0xDF, 0x8, 0x8, 0, 0},
0736     {0xE0, 0x8, 0x8, 0, 0},
0737     {0xE1, 0x8, 0x8, 0, 0},
0738     {0xE2, 0, 0, 0, 0},
0739     {0xE3, 0, 0, 0, 0},
0740     {0xE4, 0, 0, 0, 0},
0741     {0xE5, 0xf5, 0xf5, 0, 0},
0742     {0xE6, 0x30, 0x30, 0, 0},
0743     {0xE7, 0x1, 0x1, 0, 0},
0744     {0xE8, 0, 0, 0, 0},
0745     {0xE9, 0xff, 0xff, 0, 0},
0746     {0xEA, 0, 0, 0, 0},
0747     {0xEB, 0, 0, 0, 0},
0748     {0xEC, 0x22, 0x22, 0, 0},
0749     {0xED, 0, 0, 0, 0},
0750     {0xEE, 0, 0, 0, 0},
0751     {0xEF, 0, 0, 0, 0},
0752     {0xF0, 0x3, 0x3, 0, 0},
0753     {0xF1, 0x1, 0x1, 0, 0},
0754     {0xF2, 0, 0, 0, 0},
0755     {0xF3, 0, 0, 0, 0},
0756     {0xF4, 0, 0, 0, 0},
0757     {0xF5, 0, 0, 0, 0},
0758     {0xF6, 0, 0, 0, 0},
0759     {0xF7, 0x6, 0x6, 0, 0},
0760     {0xF8, 0, 0, 0, 0},
0761     {0xF9, 0, 0, 0, 0},
0762     {0xFA, 0x40, 0x40, 0, 0},
0763     {0xFB, 0, 0, 0, 0},
0764     {0xFC, 0x1, 0x1, 0, 0},
0765     {0xFD, 0x80, 0x80, 0, 0},
0766     {0xFE, 0x2, 0x2, 0, 0},
0767     {0xFF, 0x10, 0x10, 0, 0},
0768     {0x100, 0x2, 0x2, 0, 0},
0769     {0x101, 0x1e, 0x1e, 0, 0},
0770     {0x102, 0x1e, 0x1e, 0, 0},
0771     {0x103, 0, 0, 0, 0},
0772     {0x104, 0x1f, 0x1f, 0, 0},
0773     {0x105, 0, 0x8, 0, 1},
0774     {0x106, 0x2a, 0x2a, 0, 0},
0775     {0x107, 0xf, 0xf, 0, 0},
0776     {0x108, 0, 0, 0, 0},
0777     {0x109, 0, 0, 0, 0},
0778     {0x10A, 0, 0, 0, 0},
0779     {0x10B, 0, 0, 0, 0},
0780     {0x10C, 0, 0, 0, 0},
0781     {0x10D, 0, 0, 0, 0},
0782     {0x10E, 0, 0, 0, 0},
0783     {0x10F, 0, 0, 0, 0},
0784     {0x110, 0, 0, 0, 0},
0785     {0x111, 0, 0, 0, 0},
0786     {0x112, 0, 0, 0, 0},
0787     {0x113, 0, 0, 0, 0},
0788     {0x114, 0, 0, 0, 0},
0789     {0x115, 0, 0, 0, 0},
0790     {0x116, 0, 0, 0, 0},
0791     {0x117, 0, 0, 0, 0},
0792     {0x118, 0, 0, 0, 0},
0793     {0x119, 0, 0, 0, 0},
0794     {0x11A, 0, 0, 0, 0},
0795     {0x11B, 0, 0, 0, 0},
0796     {0x11C, 0x1, 0x1, 0, 0},
0797     {0x11D, 0, 0, 0, 0},
0798     {0x11E, 0, 0, 0, 0},
0799     {0x11F, 0, 0, 0, 0},
0800     {0x120, 0, 0, 0, 0},
0801     {0x121, 0, 0, 0, 0},
0802     {0x122, 0x80, 0x80, 0, 0},
0803     {0x123, 0, 0, 0, 0},
0804     {0x124, 0xf8, 0xf8, 0, 0},
0805     {0x125, 0, 0, 0, 0},
0806     {0x126, 0, 0, 0, 0},
0807     {0x127, 0, 0, 0, 0},
0808     {0x128, 0, 0, 0, 0},
0809     {0x129, 0, 0, 0, 0},
0810     {0x12A, 0, 0, 0, 0},
0811     {0x12B, 0, 0, 0, 0},
0812     {0x12C, 0, 0, 0, 0},
0813     {0x12D, 0, 0, 0, 0},
0814     {0x12E, 0, 0, 0, 0},
0815     {0x12F, 0, 0, 0, 0},
0816     {0x130, 0, 0, 0, 0},
0817     {0xFFFF, 0, 0, 0, 0}
0818 };
0819 
0820 #define LCNPHY_NUM_DIG_FILT_COEFFS 16
0821 #define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
0822 
0823 static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
0824     [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
0825     {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
0826      128, 64,},
0827     {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
0828      167, 93,},
0829     {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
0830      128, 64,},
0831     {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
0832      170, 340, 170,},
0833     {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
0834      256, 185, 256,},
0835     {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
0836      256, 273, 256,},
0837     {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
0838      256, 352, 256,},
0839     {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
0840      128, 233, 128,},
0841     {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
0842      1881, 256,},
0843     {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
0844      1881, 256,},
0845     {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
0846      384, 288,},
0847     {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
0848      128, 384, 288,},
0849     {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
0850      170, 340, 170,},
0851 };
0852 
0853 #define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
0854 static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
0855     [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
0856     {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
0857      0x278, 0xfea0, 0x80, 0x100, 0x80,},
0858     {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
0859      750, 0xFE2B, 212, 0xFFCE, 212,},
0860     {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
0861      0xFEF2, 128, 0xFFE2, 128}
0862 };
0863 
0864 #define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
0865     mod_phy_reg(pi, 0x4a4, \
0866             (0x1ff << 0), \
0867             (u16)(idx) << 0)
0868 
0869 #define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
0870     mod_phy_reg(pi, 0x4a5, \
0871             (0x7 << 8), \
0872             (u16)(npt) << 8)
0873 
0874 #define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
0875     (read_phy_reg((pi), 0x4a4) & \
0876      ((0x1 << 15) | \
0877       (0x1 << 14) | \
0878       (0x1 << 13)))
0879 
0880 #define wlc_lcnphy_get_tx_pwr_npt(pi) \
0881     ((read_phy_reg(pi, 0x4a5) & \
0882       (0x7 << 8)) >> \
0883      8)
0884 
0885 #define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
0886     (read_phy_reg(pi, 0x473) & 0x1ff)
0887 
0888 #define wlc_lcnphy_get_target_tx_pwr(pi) \
0889     ((read_phy_reg(pi, 0x4a7) & \
0890       (0xff << 0)) >> \
0891      0)
0892 
0893 #define wlc_lcnphy_set_target_tx_pwr(pi, target) \
0894     mod_phy_reg(pi, 0x4a7, \
0895             (0xff << 0), \
0896             (u16)(target) << 0)
0897 
0898 #define wlc_radio_2064_rcal_done(pi) \
0899     (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
0900 
0901 #define tempsense_done(pi) \
0902     (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
0903 
0904 #define LCNPHY_IQLOCC_READ(val) \
0905     ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
0906 
0907 #define FIXED_TXPWR 78
0908 #define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val))
0909 
0910 void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti)
0911 {
0912     wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
0913 }
0914 
0915 void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti)
0916 {
0917     wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
0918 }
0919 
0920 static void
0921 wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id,
0922                  const u16 *tbl_ptr, u32 tbl_len,
0923                  u32 tbl_width, u32 tbl_offset)
0924 {
0925     struct phytbl_info tab;
0926     tab.tbl_id = tbl_id;
0927     tab.tbl_ptr = tbl_ptr;
0928     tab.tbl_len = tbl_len;
0929     tab.tbl_width = tbl_width;
0930     tab.tbl_offset = tbl_offset;
0931     wlc_lcnphy_read_table(pi, &tab);
0932 }
0933 
0934 static void
0935 wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id,
0936                   const u16 *tbl_ptr, u32 tbl_len,
0937                   u32 tbl_width, u32 tbl_offset)
0938 {
0939 
0940     struct phytbl_info tab;
0941     tab.tbl_id = tbl_id;
0942     tab.tbl_ptr = tbl_ptr;
0943     tab.tbl_len = tbl_len;
0944     tab.tbl_width = tbl_width;
0945     tab.tbl_offset = tbl_offset;
0946     wlc_lcnphy_write_table(pi, &tab);
0947 }
0948 
0949 static u32
0950 wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
0951 {
0952     u32 quotient, remainder, roundup, rbit;
0953 
0954     quotient = dividend / divisor;
0955     remainder = dividend % divisor;
0956     rbit = divisor & 1;
0957     roundup = (divisor >> 1) + rbit;
0958 
0959     while (precision--) {
0960         quotient <<= 1;
0961         if (remainder >= roundup) {
0962             quotient++;
0963             remainder = ((remainder - roundup) << 1) + rbit;
0964         } else {
0965             remainder <<= 1;
0966         }
0967     }
0968 
0969     if (remainder >= roundup)
0970         quotient++;
0971 
0972     return quotient;
0973 }
0974 
0975 static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
0976 {
0977     int k;
0978     k = 0;
0979     if (type == 0) {
0980         if (coeff_x < 0)
0981             k = (coeff_x - 1) / 2;
0982         else
0983             k = coeff_x / 2;
0984     }
0985 
0986     if (type == 1) {
0987         if ((coeff_x + 1) < 0)
0988             k = (coeff_x) / 2;
0989         else
0990             k = (coeff_x + 1) / 2;
0991     }
0992     return k;
0993 }
0994 
0995 static void
0996 wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains)
0997 {
0998     u16 dac_gain, rfgain0, rfgain1;
0999 
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 
1012 static 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 
1023 static 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 
1034 static void
1035 wlc_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 
1060 static void
1061 wlc_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 
1097 static 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 
1107 static 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 
1113 static 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 
1129 static bool
1130 wlc_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 
1166 cleanup:
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 
1174 static 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);
1241 cleanup:
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 
1255 static 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 
1264 static 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 
1301 static bool
1302 wlc_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 
1427 stop_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 
1461 cal_done:
1462     kfree(ptr);
1463     return result;
1464 }
1465 
1466 s8 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 
1481 void 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 
1512 static 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 
1529 static void
1530 wlc_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 
1549 static void
1550 wlc_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 
1605 static void
1606 wlc_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 
1773 static int
1774 wlc_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 
1850 static 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 
1861 static 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 
1891 static 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 
1906 static 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 
1919 static 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 
1942 enum lcnphy_tssi_mode {
1943     LCNPHY_TSSI_PRE_PA,
1944     LCNPHY_TSSI_POST_PA,
1945     LCNPHY_TSSI_EXT
1946 };
1947 
1948 static void
1949 wlc_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 
1998 static 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 
2019 static 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 
2064 static 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 
2191 void 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 
2210 s32 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 
2221 static 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 
2231 void 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 
2262 static 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 
2315 static 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 
2375 static 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 
2388 void 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 
2441 static void
2442 wlc_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 
2533 static 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 
2548 static void
2549 wlc_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 
2562 static void
2563 wlc_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 
2773 cleanup:
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 
2793 static 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 
2865 static 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 
3007 static 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 
3082 static 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 
3092 void
3093 wlc_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 
3102 void 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 
3118 void 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 
3130 void 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 
3189 static 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 
3208 void 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 
3285 static void
3286 wlc_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 
3312 void 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 
3332 void
3333 wlc_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 
3396 void 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 
3427 static void
3428 wlc_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 
3472 static struct lcnphy_unsign16_struct
3473 wlc_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 
3507 static void
3508 wlc_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 
3588 static void
3589 wlc_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;
3770 cleanup:
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 
3784 void 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 
3800 static 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 
3820 u16 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 
3835 static 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 
3946 s16 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 
3988 u16 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 
4046 s8 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 
4056 s8 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 
4088 static 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 
4102 static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4103 {
4104 }
4105 
4106 static 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 
4131 static 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 
4191 void 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 
4230 void 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 
4252 void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4253 {
4254     return;
4255 
4256 }
4257 
4258 void 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 
4276 static void
4277 wlc_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 
4313 static 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 
4362 static 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 
4414 static 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 
4442 static 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 
4462 static 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 
4533 static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4534 {
4535     wlc_radio_2064_init(pi);
4536 }
4537 
4538 static 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 
4626 static 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 
4672 static 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 
4680 static 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 
4735 static 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 
4745 void 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 
4793 static 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 
4886 void 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 
4901 bool 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 
4910 void 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 
4923 void 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 
4962 void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
4963 {
4964     kfree(pi->u.pi_lcnphy);
4965 }
4966 
4967 bool 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 
5015 static 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 
5045 static 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 
5082 s32 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 }