/***************************************************************************
 *
 * Copyright 2015-2019 BES.
 * All rights reserved. All unpublished rights reserved.
 *
 * No part of this work may be used or reproduced in any form or by any
 * means, or stored in a database or retrieval system, without prior written
 * permission of BES.
 *
 * Use of this work is governed by a license granted by BES.
 * This work contains confidential and proprietary information of
 * BES. which is protected by copyright, trade secret,
 * trademark and other intellectual property rights.
 *
 ****************************************************************************/
#include "plat_types.h"
#include "hal_i2c.h"
#include "hal_uart.h"
#include "bt_drv.h"
#ifdef RTOS
#include "cmsis_os.h"
#endif
#include "cmsis.h"
#include "hal_cmu.h"
#include "hal_trace.h"
#include "hal_timer.h"
#include "tgt_hardware.h"
#include "bt_drv_internal.h"
#include "bt_drv_2300p_internal.h"
#include "hal_chipid.h"
#include "bt_drv_interface.h"
#include "bt_drv_reg_op.h"
#include "pmu.h"
#include "iqcorrect.h"
#include "hal_btdump.h"

#define AUTO_CAL                                0

#ifndef BT_RF_MAX_XTAL_TUNE_PPB
// Default 10 ppm/bit or 10000 ppb/bit
#define BT_RF_MAX_XTAL_TUNE_PPB                 10000
#endif

#ifndef BT_RF_XTAL_TUNE_FACTOR
// Default 0.2 ppm/bit or 200 ppb/bit
#define BT_RF_XTAL_TUNE_FACTOR                  200
#endif

#define DEFAULT_XTAL_FCAP                       0x8080

#define XTAL_FCAP_NORMAL_SHIFT                  0
#define XTAL_FCAP_NORMAL_MASK                   (0xFF << XTAL_FCAP_NORMAL_SHIFT)
#define XTAL_FCAP_NORMAL(n)                     BITFIELD_VAL(XTAL_FCAP_NORMAL, n)

#define BT_XTAL_CMOM_DR                         (1 << 13)

#define RF_REG_XTAL_FCAP                        0xE9
#define RF_REG_XTAL_CMOM_DR                     0xE8

/* ljh add for sync modify rf RF_REG_XTAL_FCAP value*/
#define SPI_TRIG_RX_NEG_TIMEOUT                 MS_TO_TICKS(3)

#define SPI_TRIG_NEG_TIMEOUT                    SPI_TRIG_RX_NEG_TIMEOUT


enum BIT_OFFSET_CMD_TYPE_T
{
    BIT_OFFSET_CMD_STOP = 0,
    BIT_OFFSET_CMD_START,
    BIT_OFFSET_CMD_ACK,
};

static uint16_t xtal_fcap = DEFAULT_XTAL_FCAP;
static uint16_t init_xtal_fcap = DEFAULT_XTAL_FCAP;


//rampup start     1--->2->3 rampup ok
//rampdown start 3-->2-->1-->0  rampdown ok


//3a06=3b3f
//for pa@1.8v
struct bt_drv_tx_table_t
{
    uint16_t tbl[16][3];
};


struct RF_SYS_INIT_ITEM
{
    uint16_t reg;
    uint16_t set;
    uint16_t mask;
    uint16_t delay;
};

static const struct RF_SYS_INIT_ITEM rf_sys_init_tbl[] =
{
    {0xb5,0x8000,0x8000,0},
    {0xc2,0x7188,0x7fff,0},
#ifdef LBRT
    {0xc4,0x0043,0x0043,0},//enable lbrt adc clk[6]
#else
    {0xc4,0x0003,0x0003,0},
#endif
};


//zhangzhd agc config use default 1216
#define REG_EB_VAL 0x000c
#define REG_181_VAL (0x00bf)
#define REG_EC_VAL 0x000d
#define REG_182_VAL 0x00bf
#define REG_ED_VAL 0x000e
#define REG_183_VAL 0x00bf
#define REG_EE_VAL 0x000b
#define REG_184_VAL 0x00bf
#define REG_EF_VAL 0x0007
#define REG_185_VAL 0x00bf
#define REG_F0_VAL 0x0007
#define REG_186_VAL 0x00af
#define REG_F1_VAL 0x0007
#define REG_187_VAL 0x009f
#define REG_F2_VAL 0x0007
#define REG_188_VAL 0x008f

//zhangzhd agc config end
const uint16_t rf_init_tbl_1[][3] =
{
    {0x88,0x8640,0},
    {0x8b,0x8a4a,0},//set rx flt cap,filter start up
#if defined(__FANG_HW_AGC_CFG_ADC__)
    {0xd1,0x8401,0},//set ra adc gain -3db
    {0x8e,0x0D28,0},//adc noise reduction
#else
    {0xd1,0x8403,0},//set gain
    {0x8e,0x0128,0},//adc noise reduction
#endif
    {0x90,0x8e1f,0},//enlarge txflt BW
    {0x91,0x05c0,0},//by walker 20180427
    {0x92,0x668e,0},//update by  luobin 2019/3/22
    {0x97,0x2523,0},//update by  luobin 2019.0523
    {0x98,0x1324,0},//update by  walker 2019.01.14, modify for yield
    {0x9a,0x4470,0},//div2 rc
    {0x9b,0xfd52,0},//update by  walker 2018.10.24
    {0x9c,0x180f,0},/////////luobin
    {0xa3,0x0789,0},
    {0xb0,0x0000,0},
    {0xb1,0x0000,0},
    {0xb3,0x31f3,0},//
    {0xb4,0x883c,0},
    {0xb6,0x3156,0},
    {0xb7,0x183f,0},//update by  walker 2018.07.30
    {0xb9,0x8000,0},//cap3g6 off
    {0xba,0x104e,0},
#if defined(__FANG_LNA_CFG__)
    {0xac,0x080e,0},//pre-charge set to 5us
    {0x85,0x7f00,0},//NFMI RXADC LDO rise up
    // {0xc3,0x0068,0},//add by xrz increase pll cal time 2018/10/20
    {0xc3,0x0044,0},
#else
    {0xc3,0x0050,0},
#endif
    {0xc5,0x4b50,0},//vco ictrl dr
    {0xc9,0x3a08,0},//vco ictrl
    {0xd3,0xc1c1,0},
    {0xd4,0x000f,0},
    {0xd5,0x4000,0},
    {0xd6,0x7980,0},
    {0xe8,0xe000,0},
    {0xf3,0x0c41,0},//by fang
    {0x1a6,0x0600,0},
    {0x1ae,0x6a00,0},//fastlock en
    {0x1d4,0x0000,0},
    {0x1d7,0xc4ff,0},//update by  walker 2018.10.10
    {0x1de,0x2000,0},
    {0x1df,0x2087,0},
    {0x1f4,0x2241,0},//by walker 20180427
    {0x1fa,0x03df,0},//rst needed
    {0x1fa,0x83df,0},
    {0xeb,REG_EB_VAL,0},//gain_idx:0
    {0x181,REG_181_VAL,0},
    {0xec,REG_EC_VAL,0},//gain_idx:1
    {0x182,REG_182_VAL,0},
    {0xed,REG_ED_VAL,0},//gain_idx:2
    {0x183,REG_183_VAL,0},
    {0xee,REG_EE_VAL,0},//gain_idx:3
    {0x184,REG_184_VAL,0},
    {0xef,REG_EF_VAL,0},//gain_idx:4
    {0x185,REG_185_VAL,0},
    {0xf0,REG_F0_VAL,0},//gain_idx:5
    {0x186,REG_186_VAL,0},
    {0xf1,REG_F1_VAL,0},//gain_idx:6
    {0x187,REG_187_VAL,0},
    {0xf2,REG_F2_VAL,0},//gain_idx:7
    {0x188,REG_188_VAL,0},
    {0x1d6,0x7e58,0},//set lbrt rxflt dccal_ready=1
    {0x1c8,0xdfc0,0},//en rfpll bias in lbrt mode
    {0x1c9,0xa0cf,0},//en log bias
    {0x82,0x0caa,0}, // select rfpll and cplx_dir=0 and en rxflt test
    {0xf4,0x2181,0}, // set flt_cap to match flt_gain
    {0x86,0xdc99,0},//set nfmi tmix
    {0xdf,0x2006,0},//set nfmi tmix vcm
#ifdef __HW_AGC__
    {0x1c7,0x007d,0},//open lbrt adc and vcm bias current
#endif
    {0x18c,0x0000,0},//max tx gain lbrt
    //air @ LBRT 31.5m
    {0x1d8,0x9162,0},//lbrt tx freqword
    {0x1d9,0x9162,0},//lbrt tx freqword
    {0x1da,0x9162,0},//lbrt tx freqword
    {0x1db,0x9162,0},//lbrt tx freqword
    {0x1dc,0x0000,0},//txlccap
    {0x1dd,0x0000,0},//txlccap
    {0x1ed,0x0000,0},//rxlccap
    {0x1ee,0x0000,0},//rxlccap
    {0x1e9,0x0a0a,0},//set rfpll divn in lbrt tx mode
    {0x1ea,0x0a0a,0},
    {0x1eb,0x0a0a,0},//set rfpll divn in lbrt rx mode
    {0x1ec,0x0a0a,0},
    {0x1ef,0x8a76,0},//lbrt rx freqword
    {0x1f0,0x8a76,0},//lbrt rx freqword
    {0x1f1,0x8a76,0},//lbrt rx freqword
    {0x1f2,0x8a76,0},//lbrt rx freqword
    {0x87,0x9f00,0},//{0x87,0x9f40,0}
    {0x81,0x9207,0},
    {0xce,0xfc08,0},
    {0x8A,0x4EA4,0},//  use rfpll for nfmi adclk
    //[below for ibrt]
    {0x8c,0x9100,0},
    {0xab,0x1c0c,0}, //2019.05.08 by luofei
    {0xa5,0x0404,0}, //rfpll pu time
    {0xa6,0x2D20,0}, //2019.05.23 by luobin
    {0xa8,0x2D22,0}, //2019.05.23 by luobin
    {0x1b7,0x2c00,0}, //2019.05.08 by luofei
    {0x1ad,0x9000,0}, // 2M tx filter baseband
    {0xdc,0x8820,0}, //fa pa pwrup time
    {0x8f,0x71b8,0},//tx dac by luobin
};

#ifdef __HW_AGC__
const uint16_t rf_init_tbl_1_hw_agc[][3] = //hw agc table
{
    {0xad,0xa04a,1},//hwagc en=1
    {0xCD,0x0040,0},//default 0x0000
    {0xcf,0x7f32,0},//lna gain dr=0 //default 0x0000
    {0xd0,0xe91f,0},//i2v flt gain dr=0 //default 0x0000

    {0xeb,0x0007,0},//gain_idx:0
    {0xec,0x0007,0},//gain_idx:1
    {0xed,0x0007,0},//gain_idx:2
    {0xee,0x000d,0},//gain_idx:3
    {0xef,0x000d,0},//gain_idx:4
    {0xf0,0x000d,0},//gain_idx:5
    {0xf1,0x000d,0},//gain_idx:6
    {0xf2,0x000c,0},//gain_idx:7
};
#endif //__HW_AGC__

const uint16_t rf_init_tbl_1_sw_agc[][3] = //sw agc table
{
    {0xad,0xa00a,1},//hwagc en=0
    {0xCD,0x0000,0},//default 0x0000
    {0xcf,0x0000,0},//lna gain dr=0 //default 0x0000
    {0xd0,0x0000,0},//i2v flt gain dr=0 //default 0x0000
    {0xeb,REG_EB_VAL,0},//gain_idx:0
    {0xec,REG_EC_VAL,0},//gain_idx:1
    {0xed,REG_ED_VAL,0},//gain_idx:2
    {0xee,REG_EE_VAL,0},//gain_idx:3
    {0xef,REG_EF_VAL,0},//gain_idx:4
    {0xf0,REG_F0_VAL,0},//gain_idx:5
    {0xf1,REG_F1_VAL,0},//gain_idx:6
    {0xf2,REG_F2_VAL,0},//gain_idx:7
};

uint32_t btdrv_rf_get_max_xtal_tune_ppb(void)
{
    return BT_RF_MAX_XTAL_TUNE_PPB;
}

uint32_t btdrv_rf_get_xtal_tune_factor(void)
{
    return BT_RF_XTAL_TUNE_FACTOR;
}

void btdrv_rf_init_xtal_fcap(uint32_t fcap)
{
    xtal_fcap = SET_BITFIELD(xtal_fcap, XTAL_FCAP_NORMAL, fcap);
    btdrv_write_rf_reg(RF_REG_XTAL_FCAP, xtal_fcap);
    init_xtal_fcap = xtal_fcap;
}

uint32_t btdrv_rf_get_init_xtal_fcap(void)
{
    return GET_BITFIELD(init_xtal_fcap, XTAL_FCAP_NORMAL);
}

uint32_t btdrv_rf_get_xtal_fcap(void)
{
    return GET_BITFIELD(xtal_fcap, XTAL_FCAP_NORMAL);
}

void btdrv_rf_set_xtal_fcap(uint32_t fcap, uint8_t is_direct)
{
    xtal_fcap = SET_BITFIELD(xtal_fcap, XTAL_FCAP_NORMAL, fcap);
    btdrv_write_rf_reg(RF_REG_XTAL_FCAP, xtal_fcap);
}


int btdrv_rf_xtal_fcap_busy(uint8_t is_direct)
{
    return 0;
}

void btdrv_rf_bit_offset_track_enable(bool enable)
{
    return;
}

uint32_t btdrv_rf_bit_offset_get(void)
{
    return 0;
}

uint16_t btdrv_rf_bitoffset_get(uint8_t conidx)
{
    uint16_t bitoffset;
    bitoffset = BTDIGITAL_REG(EM_BT_BITOFF_ADDR+conidx*BT_EM_SIZE) & 0x3ff;
    return bitoffset;
}

void btdrv_rf_log_delay_cal(void)
{
    unsigned short read_value;
    unsigned short write_value;
    BT_DRV_TRACE(0,"btdrv_rf_log_delay_cal\n");

    btdrv_write_rf_reg(0xa7, 0x0028);

    btdrv_write_rf_reg(0xd4, 0x0000);
    btdrv_write_rf_reg(0xd5, 0x4002);
//   *(volatile uint32_t*)(0xd02201e4) = 0x000a00b0;
    *(volatile uint32_t*)(0xd0340020) = 0x030e01c1;
    BT_DRV_TRACE(1,"0xd0340020 =%x\n",*(volatile uint32_t*)(0xd0340020) );

    btdrv_delay(1);

    btdrv_write_rf_reg(0xd2, 0x5003);

    btdrv_delay(1);

    btdrv_read_rf_reg(0x1e2, &read_value);
    BT_DRV_TRACE(1,"0x1e2 read_value:%x\n",read_value);
    if(read_value == 0xff80)
    {
        btdrv_write_rf_reg(0xd3, 0xffff);
    }
    else
    {
        write_value = ((read_value>>7)&0x0001) | ((read_value & 0x007f)<<1) | ((read_value&0x8000)>>7) | ((read_value&0x7f00)<<1);
        BT_DRV_TRACE(1,"d3 write_value:%x\n",write_value);
        btdrv_write_rf_reg(0xd3, write_value);
    }
    btdrv_delay(1);

//    *(volatile uint32_t*)(0xd02201e4) = 0x00000000;
    *(volatile uint32_t*)(0xd0340020) = 0x010e01c0;
    BT_DRV_TRACE(1,"0xd0340020 =%x\n",*(volatile uint32_t*)(0xd0340020) );


    btdrv_write_rf_reg(0xd4, 0x000f);
    btdrv_write_rf_reg(0xd2, 0x1003);
    btdrv_write_rf_reg(0xd5, 0x4000);

}

void btdrv_rf_rx_gain_adjust_req(uint32_t user, bool lowgain)
{
    return;
}

//rf Image calib
void btdtv_rf_image_calib(void)
{

    uint16_t read_val;
    //read calibrated val from efuse 0x05 register
    pmu_get_efuse(PMU_EFUSE_PAGE_SW_CFG, &read_val);
    //check if bit 11 has been set
    uint8_t calb_done_flag = ((read_val &0x800)>>11);
    if(calb_done_flag)
    {
        BT_DRV_TRACE(1,"EFUSE REG[5]=%x",read_val);
    }
    else
    {
        BT_DRV_TRACE(0,"EFUSE REG[5] rf image has not been calibrated!");
        return;
    }
    //[bit 12] calib flag
    uint8_t calib_val = ((read_val &0x1000)>>12);
    btdrv_read_rf_reg(0x9b,&read_val);
    read_val&=0xfcff;

    if(calib_val==0)
    {
        read_val|= 1<<8;
    }
    else if(calib_val== 1)
    {
        read_val|= 1<<9;
    }

    BT_DRV_TRACE(1,"write rf image calib val=%x in REG[0x9b]", read_val);
    btdrv_write_rf_reg(0x9b,read_val);
}

#ifdef TX_IQ_CAL
const uint16_t tx_cal_rfreg_set[][3] =
{
    //iq cal path
    {0x1c4,0xffcf,0},
    {0x1c5,0xf8ff,0},
    {0x1c6,0x007f,0},
    {0x1c7,0x03ff,0},
    {0x1d6,0x7a58,0},
    {0x1d7,0xc0f7,0},
    {0x1f4,0x2481,0},
    {0x94,0x11c3,0},
    {0x95,0xe5c0,0},
    {0xd1,0x846b,0},
    {0xae,0x0403,0},
    {0x86,0xccd9,0},
    {0xf3,0x0c75,0},
    {0xf4,0x0309,0},
    {0xcf,0x8090,0},
    {0x82,0x2cab,0},

    //nfmi adc
    {0xc4,0x00c3,0},
    {0xae,0x07ff,0},
    {0x85,0x470f,0},
    {0x82,0x4aab,0},
    {0x82,0xecab,0},
    {0x87,0xa211,0},
    {0x87,0xe211,0},
    {0x84,0xfff8,0},
};

const uint16_t tx_cal_rfreg_store[][1] =
{
    {0x1c4},
    {0x1c5},
    {0x1c6},
    {0x1c7},
    {0x1d6},
    {0x1d7},
    {0x1f4},
    {0x94},
    {0x95},
    {0xd1},
    {0xae},
    {0x86},
    {0xf3},
    {0xf4},
    {0xcf},
    {0x82},
    {0xc4},
    {0x85},
    {0x87},
    {0x84},
};

int bt_iqimb_ini ();
int bt_iqimb_test_ex (int mismatch_type);
void btdrv_tx_iq_cal(void)
{
    uint8_t i;
    const uint16_t (*tx_cal_rfreg_set_p)[3];
    const uint16_t (*tx_cal_rfreg_store_p)[1];
    uint32_t reg_set_tbl_size;
    uint32_t reg_store_tbl_size;
    uint16_t value;
    uint32_t tx_cal_digreg_store[5];

    tx_cal_rfreg_store_p = &tx_cal_rfreg_store[0];
    reg_store_tbl_size = sizeof(tx_cal_rfreg_store)/sizeof(tx_cal_rfreg_store[0]);
    uint16_t tx_cal_rfreg_store[reg_store_tbl_size];
    BT_DRV_TRACE(0,"reg_store:\n");
    for(i=0; i< reg_store_tbl_size; i++)
    {
        btdrv_read_rf_reg(tx_cal_rfreg_store_p[i][0],&value);
        tx_cal_rfreg_store[i] = value;
        BT_DRV_TRACE(2,"reg=%x,v=%x",tx_cal_rfreg_store_p[i][0],value);
    }
    tx_cal_digreg_store[0] = *(volatile uint32_t*)(0xd0330038);
    tx_cal_digreg_store[1] = *(volatile uint32_t*)(0xd0350364);
    tx_cal_digreg_store[2] = *(volatile uint32_t*)(0xd0350360);
    tx_cal_digreg_store[3] = *(volatile uint32_t*)(0xd035037c);
    tx_cal_digreg_store[4] = *(volatile uint32_t*)(0xd02201e4);
    BT_DRV_TRACE(1,"0xd0330038:%x\n",tx_cal_digreg_store[0]);
    BT_DRV_TRACE(1,"0xd0350364:%x\n",tx_cal_digreg_store[1]);
    BT_DRV_TRACE(1,"0xd0350360:%x\n",tx_cal_digreg_store[2]);
    BT_DRV_TRACE(1,"0xd035037c:%x\n",tx_cal_digreg_store[3]);
    BT_DRV_TRACE(1,"0xd02201e4:%x\n",tx_cal_digreg_store[4]);


    tx_cal_rfreg_set_p = &tx_cal_rfreg_set[0];
    reg_set_tbl_size = sizeof(tx_cal_rfreg_set)/sizeof(tx_cal_rfreg_set[0]);
    BT_DRV_TRACE(0,"reg_set:\n");
    for(i=0; i< reg_set_tbl_size; i++)
    {
        btdrv_write_rf_reg(tx_cal_rfreg_set_p[i][0],tx_cal_rfreg_set_p[i][1]);
        if(tx_cal_rfreg_set_p[i][2] !=0)
            btdrv_delay(tx_cal_rfreg_set_p[i][2]);//delay
        btdrv_read_rf_reg(tx_cal_rfreg_set_p[i][0],&value);
        BT_DRV_TRACE(2,"reg=%x,v=%x",tx_cal_rfreg_set_p[i][0],value);
    }
    //iq cal cordic
    *(volatile uint32_t*)(0xd0330038) = 0x0020010d;
    btdrv_delay(1);
    *(volatile uint32_t*)(0xd0350364) = 0x002eb948;
    *(volatile uint32_t*)(0xd0350360) = 0x007fc240;
    *(volatile uint32_t*)(0xd035037c) = 0x00020405;
    *(volatile uint32_t*)(0xd02201e4) = 0x000a0000;
    BT_DRV_TRACE(1,"0xd0330038:%x\n",*(volatile uint32_t*)(0xd0330038));
    BT_DRV_TRACE(1,"0xd0350364:%x\n",*(volatile uint32_t*)(0xd0350364));
    BT_DRV_TRACE(1,"0xd0350360:%x\n",*(volatile uint32_t*)(0xd0350360));
    BT_DRV_TRACE(1,"0xd035037c:%x\n",*(volatile uint32_t*)(0xd035037c));
    BT_DRV_TRACE(1,"0xd02201e4:%x\n",*(volatile uint32_t*)(0xd02201e4));

    bt_iqimb_ini();
    bt_iqimb_test_ex(1);

    BT_DRV_TRACE(0,"reg_reset:\n");
    for(i=0; i< reg_store_tbl_size; i++)
    {
        btdrv_write_rf_reg(tx_cal_rfreg_store_p[i][0],tx_cal_rfreg_store[i]);

        btdrv_read_rf_reg(tx_cal_rfreg_store_p[i][0],&value);
        BT_DRV_TRACE(2,"reg=%x,v=%x",tx_cal_rfreg_store_p[i][0],value);
    }
    *(volatile uint32_t*)(0xd0330038) = tx_cal_digreg_store[0];
    *(volatile uint32_t*)(0xd0350364) = tx_cal_digreg_store[1];
    *(volatile uint32_t*)(0xd0350360) = tx_cal_digreg_store[2];
    *(volatile uint32_t*)(0xd035037c) = tx_cal_digreg_store[3];
    *(volatile uint32_t*)(0xd02201e4) = tx_cal_digreg_store[4];
    BT_DRV_TRACE(1,"0xd0330038:%x\n",*(volatile uint32_t*)(0xd0330038));
    BT_DRV_TRACE(1,"0xd0350364:%x\n",*(volatile uint32_t*)(0xd0350364));
    BT_DRV_TRACE(1,"0xd0350360:%x\n",*(volatile uint32_t*)(0xd0350360));
    BT_DRV_TRACE(1,"0xd035037c:%x\n",*(volatile uint32_t*)(0xd035037c));
    BT_DRV_TRACE(1,"0xd02201e4:%x\n",*(volatile uint32_t*)(0xd02201e4));

}
#endif

uint8_t btdrv_rf_init(void)
{
    uint16_t value;
    const uint16_t (*rf_init_tbl_p)[3];
    uint32_t tbl_size;
    //uint8_t ret;
    uint8_t i;

    for (i = 0; i < ARRAY_SIZE(rf_sys_init_tbl); i++)
    {
        btdrv_read_rf_reg(rf_sys_init_tbl[i].reg, &value);
        value = (value & ~rf_sys_init_tbl[i].mask) | (rf_sys_init_tbl[i].set & rf_sys_init_tbl[i].mask);
        if (rf_sys_init_tbl[i].delay)
        {
            btdrv_delay(rf_sys_init_tbl[i].delay);
        }
        btdrv_write_rf_reg(rf_sys_init_tbl[i].reg, value);
    }

    rf_init_tbl_p = &rf_init_tbl_1[0];
    tbl_size = sizeof(rf_init_tbl_1)/sizeof(rf_init_tbl_1[0]);

    for(i=0; i< tbl_size; i++)
    {
        btdrv_write_rf_reg(rf_init_tbl_p[i][0],rf_init_tbl_p[i][1]);
        if(rf_init_tbl_p[i][2] !=0)
            btdrv_delay(rf_init_tbl_p[i][2]);//delay
    }

    bt_drv_tx_pwr_init();

#ifdef __HW_AGC__
    for(i=0; i< sizeof(rf_init_tbl_1_hw_agc)/sizeof(rf_init_tbl_1_hw_agc[0]); i++)
    {
        btdrv_write_rf_reg(rf_init_tbl_1_hw_agc[i][0],rf_init_tbl_1_hw_agc[i][1]);
        if(rf_init_tbl_1_hw_agc[i][2] !=0)
            btdrv_delay(rf_init_tbl_1_hw_agc[i][2]);//delay
    }
#endif

    //need before rf log delay cal
    btdtv_rf_image_calib();

    btdrv_rf_log_delay_cal();

    btdrv_spi_trig_init();

#ifdef TX_IQ_CAL
    hal_btdump_clk_enable();
    bt_iq_calibration_setup();
    hal_btdump_clk_disable();
#endif

    return 1;
}

void bt_drv_rf_reset(void)
{
    btdrv_write_rf_reg(0x80,0xcafe);
    btdrv_write_rf_reg(0x80,0x5fee);
}

static void bt_drv_switch_hw_sw_agc(enum BT_AGC_MODE_T agc_mode)
{
    static enum BT_AGC_MODE_T agc_mode_bak = BT_AGC_MODE_NONE;
    uint16_t i = 0;

    if(agc_mode_bak != agc_mode)
    {
        agc_mode_bak = agc_mode;
        BT_DRV_TRACE(1,"BT_DRV:use AGC mode=%d[1:HW,0:SW]",agc_mode);
        uint32_t lock = int_lock_global();
        if(agc_mode == BT_AGC_MODE_HW)
        {
#ifdef __HW_AGC__
            bt_drv_reg_op_hw_sw_agc_select(BT_AGC_MODE_HW);
            for(i=0; i< sizeof(rf_init_tbl_1_hw_agc)/sizeof(rf_init_tbl_1_hw_agc[0]); i++)
            {
                btdrv_write_rf_reg(rf_init_tbl_1_hw_agc[i][0],rf_init_tbl_1_hw_agc[i][1]);
                if(rf_init_tbl_1_hw_agc[i][2] !=0)
                    btdrv_delay(rf_init_tbl_1_hw_agc[i][2]);//delay
            }
#endif
        }
        else
        {
            bt_drv_reg_op_hw_sw_agc_select(BT_AGC_MODE_SW);
            for(i=0; i< sizeof(rf_init_tbl_1_sw_agc)/sizeof(rf_init_tbl_1_sw_agc[0]); i++)
            {
                btdrv_write_rf_reg(rf_init_tbl_1_sw_agc[i][0],rf_init_tbl_1_sw_agc[i][1]);
                if(rf_init_tbl_1_sw_agc[i][2] !=0)
                    btdrv_delay(rf_init_tbl_1_sw_agc[i][2]);//delay
            }
        }
        int_unlock_global(lock);
    }
}

void bt_drv_select_agc_mode(enum BT_WORK_MODE_T mode)
{
#ifdef __HYBIRD_AGC__
    enum BT_AGC_MODE_T agc_mode = BT_AGC_MODE_SW;
    switch(mode)
    {
        case BT_IDLE_MODE:
            agc_mode = BT_AGC_MODE_HW;
            break;
        case BT_A2DP_WORK_MODE:
        case BT_HFP_WORK_MODE:
            agc_mode = BT_AGC_MODE_SW;
            break;
        default:
            BT_DRV_TRACE(1,"BT_DRV:set error mork mode=%d",mode);
            break;
    }

    bt_drv_switch_hw_sw_agc(agc_mode);
#endif
}

static uint16_t efuse;
static int16_t rf18b_6_4, rf18b_10_8, rf18b_14_12;
#define TX_POWET_CALIB_FACTOR 0x2

static int check_btpower_efuse_invalid(void)
{
    pmu_get_efuse(PMU_EFUSE_PAGE_BT_POWER, &efuse);
    BT_DRV_TRACE(1,"efuse_8=0x%x",efuse);

    rf18b_6_4   = (efuse & 0x70)    >> 4;                     //address_8 [6:4]
    rf18b_10_8  = (efuse & 0x700)   >> 8;                     //address_8 [10:8]
    rf18b_14_12 = (efuse & 0x7000)  >> 12;                    //address_8 [14:12]

    if((0 == efuse)       ||
       (rf18b_6_4   > 5)  ||
       (rf18b_10_8  > 5)  ||
       (rf18b_14_12 > 5))
    {
        BT_DRV_TRACE(0,"invalid efuse value.");
        return 0;
    }

    return 1;
}

void bt_drv_tx_pwr_init(void)
{
    //ble txpower need modify ble tx idx @ bt_drv_config.c
    //modify bit4~7 to change ble tx gain
    btdrv_write_rf_reg(0x189, 0x0071); // min tx gain  2019.02.26
    btdrv_write_rf_reg(0x18a, 0x0071); // mid tx gain  2019.02.26
    if (0 == check_btpower_efuse_invalid())
        btdrv_write_rf_reg(0x18b, 0x0071); // max tx gain 2019.02.26
}

void bt_drv_tx_pwr_init_for_testmode(void)
{
    //ble txpower need modify ble tx idx @ bt_drv_config.c
    //modify bit4~7 to change ble tx gain
    btdrv_write_rf_reg(0x189, 0x007a); // min tx gain  2019.02.26
    btdrv_write_rf_reg(0x18a, 0x0076); // mid tx gain  2019.02.26
    if (0 == check_btpower_efuse_invalid())
        btdrv_write_rf_reg(0x18b, 0x0071); // max tx gain 2019.02.26
}

void btdrv_txpower_calib(void)
{
    uint16_t rf92_11_8;
    uint16_t tmp_val;
    int16_t  average_value;               //may be negative, so use signed numbers
    uint16_t read_value;

    uint16_t bit7_symbol, bit11_symbol, bit15_symbol;

    if(0 == check_btpower_efuse_invalid())
        return;

    bit7_symbol     = (efuse & 0x80)    >> 4;
    bit11_symbol    = (efuse & 0x800)   >> 8;
    bit15_symbol    = (efuse & 0x8000)  >> 12;
    rf92_11_8   = efuse & 0xf;                                //address_8 [3:0]

    BT_DRV_TRACE(3, "bit7_symbol=%d, bit11_symbol=%d, bit15_symbol=%d",
                 bit7_symbol,
                 bit11_symbol,
                 bit15_symbol);
    BT_DRV_TRACE(4, "rf92_11_8=%x, rf18b_6_4=%x, rf18b_10_8=%x, rf18b_14_12=%x",
                 rf92_11_8,
                 rf18b_6_4,
                 rf18b_10_8,
                 rf18b_14_12);

    rf18b_6_4   = (bit7_symbol == 0)  ? rf18b_6_4   : -rf18b_6_4;
    rf18b_10_8  = (bit11_symbol == 0) ? rf18b_10_8  : -rf18b_10_8;
    rf18b_14_12 = (bit15_symbol == 0) ? rf18b_14_12 : -rf18b_14_12;

    //set 0x92[11:8] begin
    btdrv_read_rf_reg(0x92,&tmp_val);
    BT_DRV_TRACE(1,"read reg 0x92 val=%x",tmp_val);
    tmp_val &= 0xf0ff;                                        //clear [11:8]
    tmp_val |= ((rf92_11_8 & 0xffff) << 8);                   //set efuse[3:0] to rf_92 [11:8]
    BT_DRV_TRACE(2,"%d write reg 0x92 val=%x",__LINE__,tmp_val);
    btdrv_write_rf_reg(0x92,tmp_val);
    //set 0x92[11:8] end

    //set 0x18b[3:0] begin
    btdrv_read_rf_reg(0x18b, &read_value);                  //0x18b

    average_value = (int16_t)(( (float)(rf18b_6_4 + rf18b_10_8 + rf18b_14_12) / 6.f) + 0.5f);
    BT_DRV_TRACE(2,"calc average_value=0x%x, dec:%d",average_value, average_value);

    if(0 < average_value)
    {
        btdrv_read_rf_reg(0x92,&tmp_val);
        tmp_val &= 0x0fff;                                      //clear [15:12]

        if(1 == average_value)
        {
            tmp_val |= ((0x8 & 0xffff) << 12);
        }
        else    //average_value [2,~]
        {
            tmp_val |= ((0xA & 0xffff) << 12);
        }
        BT_DRV_TRACE(2,"%d write reg 0x92 val=%x",__LINE__,tmp_val);
        btdrv_write_rf_reg(0x92,tmp_val);
    }

    tmp_val = TX_POWET_CALIB_FACTOR - average_value;
    if(average_value > TX_POWET_CALIB_FACTOR)
        tmp_val = 0;

    BT_DRV_TRACE(1,"finally tmp_val=%x",tmp_val);

    read_value &= 0xff00;                                  //clear [3:0] & [7:4]
    read_value |= (tmp_val | (0x7 << 4));                  //get 0x18b [3:0] & [7:4]
    btdrv_write_rf_reg(0x18b,read_value);
    BT_DRV_TRACE(1,"write reg 0x18b val=0x%x",read_value);
    //set 0x18b[3:0] end
}
