diff --git a/drivers/power/sd77426_fg_mmi/Kbuild b/drivers/power/sd77426_fg_mmi/Kbuild index fe11c32b0770..f2f6f48cae74 100644 --- a/drivers/power/sd77426_fg_mmi/Kbuild +++ b/drivers/power/sd77426_fg_mmi/Kbuild @@ -7,4 +7,5 @@ sd77426_fg_mmi-objs += oz8806_battery.o sd77426_fg_mmi-objs += parameter.o sd77426_fg_mmi-objs += table.o sd77426_fg_mmi-objs += bmulib.o +sd77426_fg_mmi-objs += calculate.o obj-m += sd77426_fg_mmi.o diff --git a/drivers/power/sd77426_fg_mmi/battery_config.h b/drivers/power/sd77426_fg_mmi/battery_config.h index 63595b5f8f36..4c72680a8326 100644 --- a/drivers/power/sd77426_fg_mmi/battery_config.h +++ b/drivers/power/sd77426_fg_mmi/battery_config.h @@ -25,7 +25,7 @@ #define OZ8806_VOLTAGE 4350 #define O2_CONFIG_CAPACITY 5158 -#define O2_CONFIG_RSENSE 20 +#define O2_CONFIG_RSENSE 10000 //Expanded 1000 times #define O2_CONFIG_EOC 200 #define OZ8806_EOD 3400 #define O2_CONFIG_BOARD_OFFSET 12 diff --git a/drivers/power/sd77426_fg_mmi/bmulib.c b/drivers/power/sd77426_fg_mmi/bmulib.c new file mode 100644 index 000000000000..e5213096f3da --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/bmulib.c @@ -0,0 +1,3395 @@ +/***************************************************************************** +* Copyright(c) O2Micro, 2019. All rights reserved. +* +* O2Micro [OZ8806] Source Code Reference Design +* File:[bmulib.c] +* +* This Source Code Reference Design for O2MICRO [OZ8806] access +* ("Reference Design") is solely for the use of PRODUCT INTEGRATION REFERENCE ONLY, +* and contains confidential and privileged information of O2Micro International +* Limited. O2Micro shall have no liability to any PARTY FOR THE RELIABILITY, +* SERVICEABILITY FOR THE RESULT OF PRODUCT INTEGRATION, or results from: (i) any +* modification or attempted modification of the Reference Design by any party, or +* (ii) the combination, operation or use of the Reference Design with non-O2Micro +* Reference Design. Use of the Reference Design is at user's discretion to qualify +* the final work result. +*****************************************************************************/ + + +/**************************************************************************************** + +****************************************************************************************/ +#include +#include +#include + +#include +#include + +#include + +#include "parameter.h" +#include "oz8806_regdef.h" +#include "table.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/***************************************************************************** +* Define section +* add all #define here +*****************************************************************************/ + +//#define FCC_UPDATA_CHARGE + +#define VERSION "2021.08.12/7.00.06 disable otp and expand rsense" +#define charge_step parameter->charge_pursue_step +#define discharge_step parameter->discharge_pursue_step +#define discharge_th parameter->discharge_pursue_th +#define config_data parameter->config + +#define RETRY_CNT 8 + +#define FORCE_OTP_MAPPING 0 + + + + + +#define SHUTDOWN_HI 50 +#define SHUTDOWN_TH1 100 +#define SHUTDOWN_TH2 300 + +#define CHARGE_END_CURRENT2 (config_data->charge_end_current +2) + +#define FCC_UPPER_LIMIT 100 +//#define FCC_LOWER_LIMIT 80 +#define FCC_LOWER_LIMIT 70 //for lianxiang + + + +#define charge_full_voltage (config_data->charge_cv_voltage - 26) +//#define full_charge_data (gas_gauge->fcc_data + config_data->design_capacity / 100 - 1) +#define full_charge_data (gas_gauge->fcc_data + gas_gauge->fcc_data / 100 - 1) +//#define full_charge_data gas_gauge->fcc_data + 2 + +#define MAX_EOD_TIME (60 * 9) //H7 add timer full +#define MAX_SUSPEND_CURRENT (-45) //H7 add wakup CAR range check, max suspend current +#define MAX_SUSPEND_CONSUME (MAX_SUSPEND_CURRENT*10/36) //H7 add wakup CAR range check, max suspend consumption(1000*mah) +#define MAX_SUSPEND_CHARGE (1800*10/36)//H7 add wakup CAR range check, max suspend charge(1000*mah) + + + + +#define ABS(a, b) ((a>b)?(a-b):(b-a)) + + + +/***************************************************************************** +* static variables section +****************************************************************************/ +static unsigned long bmu_kernel_memaddr; + bmu_data_t *batt_info; + gas_gauge_t *gas_gauge; + parameter_data_t parameter_customer; + parameter_data_t *parameter; + + int *rc_table; + int *xaxis_table; + int *yaxis_table; + int *zaxis_table; + + int32_t calculate_mah = 0; + int32_t calculate_soc = 0; +static int car_error = 0; + +static char * BATT_CAPACITY= NULL;//"/data/sCaMAH.dat"; +static char * BATT_FCC = NULL;//"/data/fcc.dat"; +static char * OCV_FLAG = NULL;//"/data/ocv_flag.dat"; +static char * BATT_OFFSET = NULL;//"/data/offset.dat"; + +static uint8_t oz8806_pec_check = 0; +static uint8_t oz8806_cell_num = 1; +static int32_t res_divider_ratio = 2000; +static uint8_t charge_end_flag = 0; + + + + int32_t one_percent_rc = 0; +//static uint8_t wait_dc_charger= 0; +//static uint8_t wait_voltage_end = 0; + +static uint8_t wait_ocv_flag = 0; +//static uint8_t wait_ocv_times = 0; + +//uint8_t enable_fast_catch_oinom = 0; +//static uint8_t oz8806_in_suspend = 0; + +//static uint8_t start_chg_count_flag = 0; + uint8_t battery_ri = 100; + +//static uint8_t charge_end = 0; +//static uint8_t charge_fcc_update = 0; +//static uint8_t discharge_fcc_update = 0; + +static uint8_t power_on_flag = 0; +//static uint8_t write_offset = 0; +//static uint8_t check_offset_flag = 0; + +static uint8_t bmu_sleep_flag = 0; +static int32_t fRSOC_PRE; + +static uint8_t discharge_end_flag = 0; +static uint8_t sleep_ocv_flag = 0; + +//static struct timex time_x; +//static struct rtc_time rtc_time; + + + +static uint32_t previous_loop_timex = 0; + +static uint8_t set_soc_from_ext = 0; +static int32_t soc_external = -1; +static uint8_t file_not_ok_cap = 30; +static uint8_t fix_car_init = 0; +static uint8_t bmu_sys_rw_kernel = 1; +static int8_t power_on_retry_times = 4; + +static uint8_t retry_times = 0; +static uint8_t calculate_times = 0; +static uint8_t times = 0; +static uint32_t time_sec = 0; + +uint8_t check_chip_function = 1; +/****************************************************************************** +* Function prototype section +* add prototypes for all functions called by this file,execepting those +* declared in header file +*****************************************************************************/ + +static void oz8806_over_flow_prevent(void); +//static void check_pec_control(void); + +static int32_t afe_register_read_byte(uint8_t index, uint8_t *dat); +static int32_t afe_register_write_byte(uint8_t index, uint8_t dat); +static int32_t afe_register_read_word(uint8_t index, uint16_t *dat); +//static int32_t afe_register_write_word(uint8_t index, uint16_t dat); + +//static int32_t afe_read_cell_volt(int32_t *voltage); +static int32_t afe_read_ocv_volt(int32_t *voltage); +//static int32_t afe_read_current(int32_t *dat); +static int32_t afe_read_car(int32_t *dat); +static int32_t afe_write_car(int32_t dat); +static int32_t afe_read_cell_temp(int32_t *date); +static int32_t afe_read_board_offset(int32_t *dat); +static int32_t afe_write_board_offset(int32_t date); + +static int32_t oz8806_read_byte( uint8_t index); +static int32_t oz8806_write_byte( uint8_t index, uint8_t data); +static int32_t oz8806_read_word(uint8_t index); +static int32_t oz8806_write_word( uint8_t index, uint16_t data); +static int32_t oz8806_cell_voltage_read(int32_t *voltage); +static int32_t oz8806_ocv_voltage_read(int32_t *voltage); +//static int32_t oz8806_temp_read(int32_t *voltage); +static int32_t oz8806_current_read(int32_t *data); +static int32_t oz8806_car_read(int32_t *car); +static int32_t oz8806_car_write(int32_t data); +static uint8_t pec_calculate (uint8_t ucCrc, uint8_t ucData); +//static int32_t oz8806_write_byte_pec(uint8_t index, uint8_t data); +//static int bmu_check_file(char * address); +static int bmu_write_data(char * address,int data); +static int bmu_read_data(char * address); +//static int bmu_write_string(char * address,char * data); +static void bmu_wait_ready(void); +//static int32_t i2c_read_byte(uint8_t addr,uint8_t index,uint8_t *data); +//static int32_t i2c_write_byte(uint8_t addr,uint8_t index,uint8_t data); +static void check_oz8806_staus(void); + +//static void discharge_end_process(void); +//static void charge_end_process(void); +static void check_board_offset(void); +static void check_shutdwon_voltage(void); + +static void trim_bmu_VD23(void); + + + +//static int32_t oz8806_write_byte_pec(uint8_t addr,uint8_t index, uint8_t data); + +void bmu_init_parameter_more(parameter_data_t *paramter_temp) +{ + if (paramter_temp->BATT_CAPACITY) + BATT_CAPACITY = paramter_temp->BATT_CAPACITY; + + if (paramter_temp->BATT_FCC) + BATT_FCC = paramter_temp->BATT_FCC; + + if (paramter_temp->OCV_FLAG) + OCV_FLAG = paramter_temp->OCV_FLAG; + + if (paramter_temp->BATT_OFFSET) + BATT_OFFSET = paramter_temp->BATT_OFFSET; + + if (paramter_temp->oz8806_cell_num) + oz8806_cell_num = paramter_temp->oz8806_cell_num; + + if (paramter_temp->res_divider_ratio) + res_divider_ratio = paramter_temp->res_divider_ratio; + + if (paramter_temp->file_not_ok_cap) + file_not_ok_cap = paramter_temp->file_not_ok_cap; + + if (paramter_temp->set_soc_from_ext) + set_soc_from_ext = paramter_temp->set_soc_from_ext; + + if (paramter_temp->fix_car_init) + fix_car_init = paramter_temp->fix_car_init; + + // if (paramter_temp->power_on_retry_times) + power_on_retry_times = paramter_temp->power_on_retry_times; + + if (!paramter_temp->bmu_sys_rw_kernel) + bmu_sys_rw_kernel = paramter_temp->bmu_sys_rw_kernel; + + //pr_err("%s\n%s\n%s\n%s\n", BATT_CAPACITY, BATT_FCC, OCV_FLAG, BATT_OFFSET); + pr_err("oz8806_cell_num:%d, res_divider_ratio: %d,file_not_ok_cap:%d, set_soc_from_ext: %d, fix_car_init:%d,power_on_retry_times:%d, bmu_sys_rw_kernel:%d\n", + oz8806_cell_num, res_divider_ratio,file_not_ok_cap, set_soc_from_ext, fix_car_init,power_on_retry_times, bmu_sys_rw_kernel); +} +/***************************************************************************** + * Description: + * bmu init chip + * Parameters: + * used to init bmu + * Return: + * None + *****************************************************************************/ + void bmu_init_chip(parameter_data_t *paramter_temp) +{ + + int32_t ret; + //uint16_t value; + uint8_t i; + int32_t data; + uint8_t * addr; + config_data_t * config_test; + uint32_t byte_num = num_0; + + byte_num = sizeof(config_data_t) + sizeof(bmu_data_t) + sizeof(gas_gauge_t); + + memset((uint8_t *)bmu_kernel_memaddr,num_0,byte_num); + + parameter = paramter_temp; + addr = (uint8_t *)(parameter->config); + for(byte_num = num_0;byte_num < sizeof(config_data_t);byte_num++) + { + *((uint8_t *)bmu_kernel_memaddr + byte_num) = *addr++; + } + + config_test = (config_data_t *)bmu_kernel_memaddr; + + batt_info = (bmu_data_t *)((uint8_t *)bmu_kernel_memaddr + byte_num); + + //-------------------------------------------------------------------------------------------------- + batt_info->Battery_ok = 1; + batt_info->i2c_error_times = num_0; + + byte_num += sizeof(bmu_data_t); + + gas_gauge = (gas_gauge_t *)((uint8_t *)bmu_kernel_memaddr + byte_num); + byte_num += sizeof(gas_gauge_t); + //-------------------------------------------------------------------------------------------------- + gas_gauge->bmu_init_ok = 0; + gas_gauge->charge_end = num_0; + gas_gauge->charge_end_current_th2 = CHARGE_END_CURRENT2; + gas_gauge->charge_strategy = 1; + gas_gauge->charge_max_ratio = 3500; + //gas_gauge->charge_max_ratio = 10000; // for lianxiang + + + gas_gauge->discharge_end = num_0; + gas_gauge->discharge_current_th = DISCH_CURRENT_TH; + gas_gauge->discharge_strategy = 1; + gas_gauge->discharge_max_ratio = 8000; // for lianxiang + + gas_gauge->dsg_end_voltage_hi = SHUTDOWN_HI; + + gas_gauge->batt_ri = 120; // charging. It is related to voltage when full charging condition. + gas_gauge->line_impedance = 0; //charging + gas_gauge->max_chg_reserve_percentage = 1000; + gas_gauge->fix_chg_reserve_percentage = 0; + gas_gauge->fast_charge_step = 2; + gas_gauge->start_fast_charge_ratio = 1500; + gas_gauge->charge_method_select = 0; + gas_gauge->max_charge_current_fix = 2000; + + //add this for oinom, start + gas_gauge->lower_capacity_reserve = 0; + gas_gauge->lower_capacity_soc_start =30; + + gas_gauge->percent_10_reserve = 0; + //add this for oinom, end + + //this for test gas gaugue + if(parameter->config->debug) + gas_gauge->dsg_end_voltage_hi = 0; + gas_gauge->dsg_end_voltage_th1 = SHUTDOWN_TH1; + gas_gauge->dsg_end_voltage_th2 = SHUTDOWN_TH2; + gas_gauge->dsg_count_2 = num_0; + + gas_gauge->overflow_data = num_32768 * num_5 * 1000 / config_data->fRsense; + bmu_dbg("yyyy gas_gauge->overflow_data is %d\n",gas_gauge->overflow_data); + + bmu_init_gg(gas_gauge); + + //-------------------------------------------------------------------------------------------------- +#ifdef OZ8806_API + //bmu_init_charge_data(((uint8_t *)bmu_kernel_memaddr + byte_num), 4*gas_gauge->charge_table_num* 2); + //byte_num += 4 * gas_gauge->charge_table_num * 2; + + xaxis_table = (int *)((uint8_t *)bmu_kernel_memaddr + byte_num); + bmu_init_XAxisElement(((uint8_t *)bmu_kernel_memaddr + byte_num), 4*gas_gauge->rc_x_num ); + byte_num += 4*gas_gauge->rc_x_num ; + + yaxis_table = (int *)((uint8_t *)bmu_kernel_memaddr + byte_num); + bmu_init_YAxisElement(((uint8_t *)bmu_kernel_memaddr + byte_num), 4*gas_gauge->rc_y_num); + byte_num += 4*gas_gauge->rc_y_num; + + zaxis_table = (int *)((uint8_t *)bmu_kernel_memaddr + byte_num); + bmu_init_ZAxisElement(((uint8_t *)bmu_kernel_memaddr + byte_num), 4*gas_gauge->rc_z_num); + byte_num += 4*gas_gauge->rc_z_num; + + rc_table = (int *)((uint8_t *)bmu_kernel_memaddr + byte_num); + bmu_init_RCtable(((uint8_t *)bmu_kernel_memaddr + byte_num), 4*gas_gauge->rc_x_num *gas_gauge->rc_y_num*gas_gauge->rc_z_num); + byte_num += 4*gas_gauge->rc_x_num *gas_gauge->rc_y_num*gas_gauge->rc_z_num; + +#else + + bmu_init_table(&xaxis_table, &yaxis_table, &zaxis_table, &rc_table); + +#endif + + pr_err("byte_num is %d\n",byte_num); + + power_on_flag = num_0; + bmu_sleep_flag = num_0; + + one_percent_rc = config_data->design_capacity / num_100; + + pr_err("AAAA O2MICRO OZ8806 DRIVER VERSION is %s\n",VERSION); + + pr_err("OZ8806 test parameter:Rsense:%d, RTempPullup:%d, VTempRef:%d, CarLSB:%d, CurLSB:%d, VolLSB:%d, FCC:%d, CV:%d, EOC:%d, EOD:%d, BoardOffset:%d, Debug:%d\n", + config_test->fRsense, + config_test->temp_pull_up, + config_test->temp_ref_voltage, + config_test->dbCARLSB, + config_test->dbCurrLSB, + config_test->fVoltLSB, + config_test->design_capacity, + config_test->charge_cv_voltage, + config_test->charge_end_current, + config_test->discharge_end_voltage, + config_test->board_offset, + config_test->debug + + ); + + //check_pec_control(); + //move check_oz8806_status here to avoid iic-commu-issue + check_oz8806_staus(); + trim_bmu_VD23(); + /* + * board offset current is measured and reg0x18 value is updated only + * after reset(power on reset or software reset), + */ + if (oz8806_get_boot_up_time() < 625) + { + pr_err("AAAA wait for current offset detection\n"); + msleep(625 - oz8806_get_boot_up_time()); + afe_register_read_word(OZ8806_OP_BOARD_OFFSET,(uint16_t *)&data); + } + + bmu_dbg("AAAAAAAAAAAAA Register BOARD_OFFSET: 0x%02x\n",data); + + ret = afe_read_board_offset(&data); + pr_err("AAAA board_offset is %d mA\n",data); + + + if(ret >= num_0) + { + + if(config_data->board_offset != num_0) + { + afe_write_board_offset(config_data->board_offset); + } + else if((data > num_10) || (data <= num_0)) + afe_write_board_offset(num_7); + } + + //wake up OZ8806 into FullPower mode + + pr_err("oz8806_cell_num is %d\n",oz8806_cell_num); + + if(oz8806_cell_num > num_1) + afe_register_write_byte(OZ8806_OP_CTRL,num_0x2c); + else + afe_register_write_byte(OZ8806_OP_CTRL,num_0x20); + + ret = afe_register_read_byte(OZ8806_OP_CTRL,&i); + pr_err("first read reg[0x09]= 0x%02x, ret = %d\n", i, ret); + + if((i & num_0x40) || (ret < num_0)) + { + if(oz8806_cell_num > num_1) + { + afe_register_write_byte(OZ8806_OP_CTRL,num_0x2c); + } + else + afe_register_write_byte(OZ8806_OP_CTRL,0x20); + bmu_dbg("Wake up oz8806 write op_ctrl 0x20 \n"); + + ret = afe_register_read_byte(OZ8806_OP_CTRL,&i); + pr_err("second read reg[0x09]= 0x%02x, ret = %d\n", i, ret); + + } + + pr_err("O2MICRO OZ8806 parameter %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,\n", + config_data->fRsense, + config_data->temp_pull_up, + config_data->temp_ref_voltage, + config_data->dbCARLSB, + config_data->dbCurrLSB, + config_data->fVoltLSB, + config_data->design_capacity, + config_data->charge_cv_voltage, + config_data->charge_end_current, + config_data->discharge_end_voltage, + config_data->board_offset, + config_data->debug + + ); + + //check_oz8806_staus(); + + //trim_bmu_VD23(); +} + + +/***************************************************************************** + * Description: + * wait ocv flag + * Parameters: + * None + * Return: + * None + *****************************************************************************/ + void wait_ocv_flag_fun(void) +{ + + int32_t ret; + uint16_t value; + uint8_t i; + int32_t data; +#if 1 + if (oz8806_get_boot_up_time() < 2000) // ocv can be stable after oz8806 is wakeuped for 2 s + { + pr_err("wait ocv flag register ready 1\n"); + msleep(2000 - oz8806_get_boot_up_time()); + oz8806_get_boot_up_time(); + //return; + } + + if (oz8806_get_power_on_time() < 2250) + { + pr_err("wait ocv flag register ready 2\n"); + msleep(2250 - oz8806_get_power_on_time()); + oz8806_get_power_on_time(); + } +#endif + + wait_ocv_flag = 1; + + for(i = 0;i < 3;i++) + { + ret = afe_register_read_word(OZ8806_OP_OCV_LOW,&value); + if(ret >= 0) + { + if ((value & POWER_OCV_FLAG) || (value & SLEEP_OCV_FLAG)) + { + if (oz8806_get_power_on_time() < 4250)//2250+2000 + { + pr_err("ocv or sleep_ocv: wait for normal scan cycle\n"); + msleep(4250 - oz8806_get_power_on_time()); + oz8806_get_power_on_time(); + } + } + else if (oz8806_get_boot_up_time() < 2250) + { + pr_err("normal ok: wait for normal scan cycle\n"); + msleep(2250 - oz8806_get_boot_up_time()); + } + break; + } + } + + //read data + afe_read_cell_volt(&batt_info->fVolt); + afe_read_current(&batt_info->fCurr); + afe_read_cell_temp(&batt_info->fCellTemp); + afe_read_car(&batt_info->fRC); + + batt_info->fRSOC = batt_info->fRC * num_100; + batt_info->fRSOC = batt_info->fRSOC / config_data->design_capacity ; + + + pr_err("read batt_info.fVolt is %d\n",(batt_info->fVolt * oz8806_cell_num)); + pr_err("read batt_info.fRC is %d\n",batt_info->fRC); + pr_err("read batt_info.fCurr is %d\n",batt_info->fCurr); + pr_err("read ocv flag ret is 0x%02x,value is 0x%02x\n",ret,value); + pr_err("read fCellTemp is %d\n",batt_info->fCellTemp); + if (ret >= num_0 ) + { + // OZ8806 First power on + if (value & POWER_OCV_FLAG) + { + power_on_flag = num_1; + afe_read_ocv_volt(&batt_info->fOCVVolt); + + afe_read_cell_volt(&batt_info->fVolt); + + if(oz8806_cell_num > num_1) + batt_info->fOCVVolt = batt_info->fVolt; + + pr_err("AAAA ocv volt is %d\n",(batt_info->fOCVVolt * oz8806_cell_num)); + pr_err("AAAA volt is %d\n",(batt_info->fVolt * oz8806_cell_num)); + + + if(batt_info->fOCVVolt > (config_data->charge_cv_voltage + 70)){ + afe_read_cell_volt(&batt_info->fVolt); + batt_info->fOCVVolt = batt_info->fVolt; + pr_err("AAAAA ocv data errror ,so batt_info->fVolt is %d\n",batt_info->fVolt); + } + + afe_read_current(&batt_info->fCurr); + pr_err("AAAA batt_info.fCurr is %d\n",batt_info->fCurr); + + if(batt_info->fCurr > num_50) + data = batt_info->fOCVVolt - num_100; + else + data = batt_info->fOCVVolt; + + batt_info->fRSOC = one_latitude_table(parameter->ocv_data_num,parameter->ocv,data); + pr_err("find ocv table batt_info.fRSOC is %d\n",batt_info->fRSOC); + + if((batt_info->fRSOC >num_100) || (batt_info->fRSOC < num_0)) + batt_info->fRSOC = num_50; + + batt_info->fRC = batt_info->fRSOC * config_data->design_capacity / num_100; + + afe_read_current(&batt_info->fCurr); + + + + if(batt_info->fRC >= (gas_gauge->overflow_data -num_10)) + { + batt_info->fRC = gas_gauge->overflow_data - gas_gauge->overflow_data /num_100; + batt_info->fRCPrev = batt_info->fRC; + } + + afe_write_car(batt_info->fRC); + batt_info->fRCPrev = batt_info->fRC; + gas_gauge->fcc_data= config_data->design_capacity * 100/100; + + + pr_err("Power on mode is activated \n"); + + + batt_info->sCaMAH = batt_info->fRSOC * config_data->design_capacity / num_100; + gas_gauge->sCtMAH = batt_info->sCaMAH; + gas_gauge->discharge_sCtMAH = config_data->design_capacity - batt_info->sCaMAH; + + } + else if(value & SLEEP_OCV_FLAG) + { + afe_read_ocv_volt(&batt_info->fOCVVolt); + sleep_ocv_flag = 1; + pr_err("Sleep ocv mode is activated \n"); + } + else + pr_err("Normal mode is activated \n"); + } + else + { + pr_err("AAAA O2MICRO OZ8806 DRIVER \n"); + pr_err("AAAA O2MICRO OZ8806 read OZ8806_OP_OCV_LOW\n"); + + } + + //for ifive +#if 0 + afe_read_car(&batt_info->fRC); + if((batt_info->fRC < (one_percent_rc)) && (batt_info->fRC > -3000)) + { + bmu_dbg("yyyy fRC will over fRC is %d\n",batt_info->fRC); + + batt_info->fRC = one_percent_rc - num_1; + afe_write_car(batt_info->fRC); + batt_info->fRCPrev = batt_info->fRC; + } + afe_read_car(&batt_info->fRC); + pr_err("fRC is %d\n",batt_info->fRC); +#endif + + + + afe_register_read_byte(num_0,&i); + pr_err("O2micro regeidter 0x00 is 0x%02x\n",i); + + afe_register_read_byte(num_9,&i); + pr_err("O2micro regeidter 0x09 is 0x%02x\n",i); +} + +/***************************************************************************** + * Description: + * trim_bmu_VD23 + * Parameters: + * None + * Return: + * None + *****************************************************************************/ + void trim_bmu_VD23(void) +{ + int32_t ret; + uint8_t i; + uint16_t value; + uint8_t data; + uint8_t temp; + + + for(i = 0;i < 3;i++) + { + ret = afe_register_read_word(OZ8806_OP_VD23,&value); + if(ret >= 0)break; + } + if(ret < 0) + { + pr_err("READ OZ8806_OP_VD23 fail and return:%d\n",ret); + return; + } + pr_err("READ oz8806 REG 0x03 is 0x%02x\n",value); + data = ((value >> 6) & 0x02) | ((value >> 8) & 0x01); + data &= 0x03; + pr_err("So trim is 0x%02x\n",data); + + for(i = 0;i < 3;i++) + { + ret = afe_register_read_byte(OZ8806_OP_PEC_CTRL,&temp); + if(ret >= 0)break; + } + if(ret < 0) + { + pr_err("READ OZ8806_OP_PEC_CTRL fail and return:%d\n",ret); + return; + } + + + + pr_err("READ oz8806 REG 0x08 is 0x%02x\n",temp); + + + temp &= (~0x03); + + if(data != 0x02) + { + temp |= data; + for(i = 0;i < 3;i++) + { + ret = afe_register_write_byte(OZ8806_OP_PEC_CTRL,temp); + pr_err("write1 oz8806 REG 0x08 is 0x%02x\n",temp); + if(ret >= 0)break; + } + + } + else + { + temp |= 0x03; + for(i = 0;i < 3;i++) + { + ret = afe_register_write_byte(OZ8806_OP_PEC_CTRL,temp); + pr_err("write2 oz8806 REG 0x08 is 0x%02x\n",temp); + if(ret >= 0)break; + } + + } + + ret = afe_register_read_byte(OZ8806_OP_PEC_CTRL,&temp); + pr_err("oz8806 REG 0x08 is 0x%02x\n",temp); + +} + +/***************************************************************************** +* Description: +* check shudown voltage control +* Parameters: +* None +* Return: +* None +*****************************************************************************/ + void check_shutdwon_voltage(void) +{ + //int32_t ret; + //uint8_t i; + int32_t temp; + //int32_t infVolt; + afe_read_cell_volt(&batt_info->fVolt); + + + if(!sleep_ocv_flag) return; + + temp = one_latitude_table(parameter->ocv_data_num,parameter->ocv,batt_info->fOCVVolt); + pr_err("Sleep data is %d \n",temp); + + + // select higher data + if(calculate_soc > temp) + temp = calculate_soc; + + //Very dangerous + if((batt_info->fRSOC - temp) > 20 + || (batt_info->fVolt < (config_data->discharge_end_voltage - 50) && temp <= 5)) + { + + //batt_info->fRSOC -= 5; + batt_info->fRSOC = temp; + if(batt_info->fRSOC < 0) batt_info->fRSOC = 0; + + batt_info->sCaMAH = batt_info->fRSOC * gas_gauge->fcc_data/ 100; + + batt_info->fRC= batt_info->sCaMAH; + if(batt_info->fRC > (gas_gauge->overflow_data - 20)) + batt_info->fRC = gas_gauge->overflow_data - 20; + afe_write_car(batt_info->fRC); + + batt_info->fRCPrev = batt_info->fRC; + + gas_gauge->sCtMAH = batt_info->sCaMAH; + if(gas_gauge->fcc_data > batt_info->sCaMAH) + gas_gauge->discharge_sCtMAH = gas_gauge->fcc_data- batt_info->sCaMAH; + else + gas_gauge->discharge_sCtMAH = 0; + } + + +} + + + + +/***************************************************************************** +* Description: +* check_oz8806_staus +* Parameters: +* None +* Return: +* None +*****************************************************************************/ +static void check_oz8806_staus(void) +{ + + +} + + + + + +/***************************************************************************** +* Description: +* bmu_wait_ready +* Parameters: +* None +* Return: +* None +*****************************************************************************/ +static void bmu_wait_ready(void) +{ + int32_t store_rc = INIT_CAP; + //int32_t fcc; + uint8_t i; + int32_t ret; + uint16_t value; + + int32_t calculate_soc_temp; + + int32_t file_soc_temp; + + pr_err("AAAA bmu wait times %d \n",times); + times ++; + //wake up OZ8806 into FullPower mode + oz8806_wakeup_full_power(); + + ret = afe_register_read_byte(OZ8806_OP_CTRL,&i); + batt_info->Battery_ok = i & BI_STATUS; + pr_err("bmu_wait_ready read 0x09 ret is %d,i is 0x%02x\n",ret,i); + + if((i & 0x40) || (ret < 0)) + { + if(oz8806_cell_num > 1) + { + afe_register_write_byte(OZ8806_OP_CTRL,0x2c); + } + else + afe_register_write_byte(OZ8806_OP_CTRL,0x20); + pr_err("oz8806 wake up function\n"); + + ret = afe_register_read_byte(OZ8806_OP_CTRL,&i); + pr_err("bmu_wait_ready read 0x09 ret is %d,i is 0x%02x\n",ret,i); + } + + //do we need add check ocv flag now? + ret = afe_register_read_word(OZ8806_OP_OCV_LOW,&value); + if ((ret >= 0) && (value & POWER_OCV_FLAG)) + { + pr_err("read flag too late\n"); + wait_ocv_flag_fun(); + } + + if (oz8806_get_power_on_time() < 2250) + { + pr_err("wait for normal scan cycle"); + msleep(2250 - oz8806_get_power_on_time()); + } + + afe_read_cell_temp(&batt_info->fCellTemp); + afe_read_cell_volt(&batt_info->fVolt); + afe_read_current(&batt_info->fCurr); + afe_read_car(&batt_info->fRC); + + + pr_err("fVolt is %d\n",(batt_info->fVolt * oz8806_cell_num)); + pr_err("fCurr is %d\n",batt_info->fCurr); + pr_err("ftemp is %d\n",batt_info->fCellTemp); + pr_err("fRC is %d\n",batt_info->fRC); + + // every time we check this and print to see if the voltage and temp and current is abnormal + // how about if rc_result error + + calculate_soc_temp = calculate_soc_result(); + + calculate_soc = calculate_soc_temp; + calculate_mah = calculate_soc * config_data->design_capacity / num_100; + + calculate_times++; +#if 0 + if (calculate_times <= calculate_retry_times) + return; +#endif + pr_err("calculate_times: %d\n",calculate_times); + + gas_gauge->fcc_data = config_data->design_capacity; + + if((batt_info->fRC > 5)&& (!power_on_flag)) + { + store_rc = batt_info->fRC; + //calculate_retry_times = 0; + pr_err("Success to get soc from car :%d\n", batt_info->fRC); + goto file_ok; + } + + if (oz8806_get_boot_up_time() < 5000) // voltage can be stable after oz8806 is powered for 5 s + { + pr_err("wait oz8806 ADC ready\n"); + return; + } + + + if((set_soc_from_ext)) + { + soc_external = oz8806_get_soc_from_ext(); + + pr_err("soc from external: %d\n", soc_external); + + if (soc_external == -1) + { + pr_err("wait for external soc:%d, retry:%d\n", soc_external, retry_times); + + if(retry_times >= 0) + { + pr_err("fail to get externl soc, retry_times:%d \n",retry_times); + retry_times = 0; + set_soc_from_ext = 0; + pr_err("can't get external soc,so make set_soc_from_ext 0\n"); + } + else + { + retry_times++; + return; + } + } + else if ((soc_external <= 100) && (soc_external >= 0)) + { + pr_err("Success to get soc from external :%d\n", soc_external); + + store_rc = soc_external * gas_gauge->fcc_data / 100; + store_rc += gas_gauge->fcc_data / 200; // + fcc / 100 * / 2 + pr_err("stored RC:%d\n", store_rc); + + goto file_ok; + } + else + { + pr_err("Error to get wrong soc from external :%d\n", soc_external); + retry_times = 0; + set_soc_from_ext = 0; + pr_err("can't get external soc,so make set_soc_from_ext 0\n"); + } + } + + if (bmu_sys_rw_kernel) + { + /* wait for sysfs to capacity from file*/ + store_rc = bmu_read_data(BATT_CAPACITY); + + //check file ,if file not exit, goto file fail + if(store_rc < 0) + { + pr_err("open BATT_CAPACITY fail, retry_times:%d \n", retry_times); + if(retry_times >= power_on_retry_times) + { + pr_err("BATT_CAPACITY file fail\n"); + batt_info->sCaMAH = calculate_mah; + goto file_fail; + } + else + { + retry_times++; + return; + } + } + pr_err("open BATT_CAPACITY success, retry_times:%d \n", retry_times); + pr_err("AAAA read battery capacity data is %d\n", store_rc); + } + else + { + store_rc = oz8806_get_save_capacity(); + + pr_err("RC from file:%d\n", store_rc); + if (store_rc == INIT_CAP) + { + pr_err("wait for reading file:%s, retry:%d\n", BATT_CAPACITY, retry_times); + if(retry_times > 10) + { + pr_err("fail to get save_capacity, retry_times:%d \n",retry_times); + goto file_fail; + } + retry_times++; + return; + } + else if (store_rc == NO_FILE) { + pr_err("no file %s, retry_times:%d \n", BATT_CAPACITY, retry_times); + goto file_fail; + } + } + +file_ok: + + //file_soc_temp: soc read from file + if (soc_external != -1) + file_soc_temp = soc_external; + else + file_soc_temp = store_rc * 100 / gas_gauge->fcc_data; + + //file ok, if ocv power on + if(power_on_flag) + { + pr_err("bmu_wait_ready, power on ok \n"); + gas_gauge->ocv_flag = 1; + + //file_soc_temp: soc read from file + //batt_info->fRSOC: calculated using OCV + //calculated_soc: calculated using VI + pr_err("soc from file:%d, vi soc:%d, ocv soc:%d \n", + file_soc_temp, calculate_soc, batt_info->fRSOC); + + pr_err("RC from file:%d, vi RC:%d, ocv RC:%d \n", + store_rc, calculate_mah, batt_info->sCaMAH); + + if((batt_info->fRSOC > 90)&& (file_soc_temp > 90)) + { + batt_info->sCaMAH = store_rc; + pr_err("start sCaMAH high USE file\n"); + } + else if(batt_info->fCurr >= 0) + { + if( ABS(calculate_soc,file_soc_temp) > 30) + { + batt_info->sCaMAH = calculate_mah; + pr_err("start sCaMAH chg USE vi\n"); + } + else // file + { + batt_info->sCaMAH = store_rc; + pr_err("start sCaMAH chg USE file\n"); + } + } + else //discharging + { + if( ABS(file_soc_temp,calculate_soc) > 20 + || (batt_info->fVolt < (config_data->discharge_end_voltage - 50) && file_soc_temp<=5)) + { + batt_info->sCaMAH = calculate_mah; + pr_err("start sCaMAH USE vi\n"); + } + else + { + batt_info->sCaMAH = store_rc; + pr_err("start sCaMAH USE file\n"); + } + } + } + //if not ocv power on + else + { pr_err("bmu_wait_ready, normal ok \n"); + gas_gauge->ocv_flag = 0; + afe_read_car(&batt_info->fRC); + + pr_err("RC from file: %d ,RC from register: %d\n", store_rc, batt_info->fRC); + + if ((batt_info->fCurr > 0 && batt_info->fRC <= 2) + || (batt_info->fCurr <= 0 && batt_info->fRC <= 0))//power on, no ocv flag + { + if((ABS(file_soc_temp,calculate_soc) > 30) + || (batt_info->fVolt < (config_data->discharge_end_voltage - 50) && file_soc_temp<=5)) + { + batt_info->sCaMAH = calculate_mah; + pr_err("file ok but USE vi,fRC<=0\n"); + } + else + { + batt_info->sCaMAH = store_rc; + pr_err("file ok USE file\n"); + } + } + else + { + // car and file changed more than 1% + if(( ABS(batt_info->fRC,store_rc) > (one_percent_rc))) + { + batt_info->sCaMAH = batt_info->fRC; + pr_err("file ok USE RC\n"); + } + else + { + //prevent issue: when reboot frequently, soc -= 1 every reboot + if (((soc_external <= 100) && (soc_external >= 0)) + &&(batt_info->fRC > store_rc) + &&(batt_info->fRC - store_rc <= one_percent_rc)) + { + pr_err("file ok USE RC\n"); + batt_info->sCaMAH = batt_info->fRC; + } + else + { + batt_info->sCaMAH = store_rc; + pr_err("file ok USE file\n"); + } + } + } + } + +file_fail: + if(store_rc<0) //fail to red fil or no file exist + { + if(power_on_flag) + { + pr_err("fVolt %dmv, oz8806_cell_num:%d, power_on_100_vol:%dmv\n",batt_info->fVolt,oz8806_cell_num,gas_gauge->power_on_100_vol); + if((batt_info->fVolt * oz8806_cell_num)>= gas_gauge->power_on_100_vol) + batt_info->sCaMAH = full_charge_data; + else + batt_info->sCaMAH = calculate_mah; + pr_err("bmu_wait_ready, power on ok and file fail \n"); + pr_err("file fail USE vi\n"); + } + else + { + pr_err("bmu_wait_ready, normal on ok and file fail \n"); + afe_read_car(&batt_info->fRC); + + pr_err("RC from register: %d, RC from vi: %d\n", batt_info->fRC, calculate_mah); + + if ((batt_info->fCurr > 0 && batt_info->fRC <= 2) + || (batt_info->fCurr <= 0 && batt_info->fRC <= 0))//power on, no ocv flag + { + pr_err("big error first power on and ocv flag not set: %d ,%d\n", batt_info->fRC, calculate_mah); + batt_info->sCaMAH = calculate_mah; + pr_err("file fail USE vi\n"); + } + else + { +#if 0 + batt_info->sCaMAH = batt_info->fRC; + pr_err("file fail USE RC\n"); +#else + + if(batt_info->fRC < one_percent_rc ) //if CAR < 1% + file_not_ok_cap = 30; + + if( ABS(batt_info->fRC,calculate_mah) > (file_not_ok_cap * config_data->design_capacity / num_100)) + { + batt_info->sCaMAH = calculate_mah; + pr_err("file fail USE vi\n"); + + } + else + { + batt_info->sCaMAH = batt_info->fRC; + pr_err("file fail USE RC\n"); + } + + if(fix_car_init) + { + batt_info->sCaMAH = batt_info->fRC; + pr_err("file fail fix fRC: %d,%d \n",batt_info->sCaMAH,batt_info->fRC); + } +#endif + } + } + } + + if(batt_info->sCaMAH <= num_0) + { + pr_err("calculate_soc is %d\n",calculate_soc); + afe_read_cell_volt(&batt_info->fVolt); + batt_info->fRSOC = calculate_soc; + if((batt_info->fRSOC >num_100) || (batt_info->fRSOC < num_0)) + batt_info->fRSOC = num_50; + + pr_err("batt_info->fRSOC is %d\n",batt_info->fRSOC); + batt_info->fRC = batt_info->fRSOC * config_data->design_capacity / num_100; + pr_err("batt_info->fRC is %d\n",batt_info->fRC); + if(batt_info->fRC >= (gas_gauge->overflow_data -num_10)) + { + batt_info->fRC = gas_gauge->overflow_data - gas_gauge->overflow_data/num_100; + batt_info->fRCPrev = batt_info->fRC; + } + + pr_err("batt_info->fRC is %d\n",batt_info->fRC); + + afe_write_car(batt_info->fRC); + batt_info->fRCPrev = batt_info->fRC; + + batt_info->sCaMAH = batt_info->fRC; + + + } + + if(batt_info->sCaMAH > full_charge_data) + { + batt_info->sCaMAH = full_charge_data; + } + pr_err("batt_info->sCaMAH is %d\n",batt_info->sCaMAH); + + batt_info->fRSOC = batt_info->sCaMAH * num_100; + batt_info->fRSOC = batt_info->fRSOC / gas_gauge->fcc_data ; + + //check if batt_info->sCaMAH == soc_external * gas_gauge->fcc_data / 100; + if ((soc_external <= 100) && (soc_external >= 0)) + if (batt_info->sCaMAH == soc_external * gas_gauge->fcc_data / 100) + batt_info->fRSOC = soc_external; + + //batt_info->fRC = batt_info->fRSOC * gas_gauge->fcc_data / num_100;//this make result smaller + batt_info->fRC = batt_info->sCaMAH; + if(batt_info->fRC >= (gas_gauge->overflow_data -num_10)) + { + batt_info->fRC = gas_gauge->overflow_data - gas_gauge->overflow_data/num_100; + batt_info->fRCPrev = batt_info->fRC; + } + + gas_gauge->sCtMAH = batt_info->sCaMAH; + + pr_err("AAAA batt_info->fVolt is %d\n",(batt_info->fVolt * oz8806_cell_num)); + pr_err("AAAA batt_info->fRSOC is %d\n",batt_info->fRSOC); + pr_err("AAAA batt_info->sCaMAH is %d\n",batt_info->sCaMAH); + pr_err("AAAA gas_gauge->sCtMAH is %d\n",gas_gauge->sCtMAH); + pr_err("AAAA fcc is %d\n",gas_gauge->fcc_data); + pr_err("AAAA batt_info->fRC is %d\n",batt_info->fRC); + pr_err("AAAA batt_info->fCurr is %d\n",batt_info->fCurr); + + afe_write_car(batt_info->fRC); + batt_info->fRCPrev = batt_info->fRC; + + if(gas_gauge->fcc_data > batt_info->sCaMAH) + gas_gauge->discharge_sCtMAH = gas_gauge->fcc_data- batt_info->sCaMAH; + else + gas_gauge->discharge_sCtMAH = 0; + + if(batt_info->fRSOC <= num_0) + { + gas_gauge->discharge_end = num_1; + batt_info->fRSOC = num_0; + gas_gauge->sCtMAH = num_0; + gas_gauge->ocv_flag = 0; + bmu_write_data(OCV_FLAG,0); + } + if(batt_info->fRSOC >= num_100) + { + gas_gauge->charge_end = num_1; + charge_end_flag = num_1; + batt_info->fRSOC = num_100; + gas_gauge->discharge_sCtMAH = num_0; + gas_gauge->discharge_fcc_update = num_1; + gas_gauge->ocv_flag = 0; + bmu_write_data(OCV_FLAG,0); + } + + if(sleep_ocv_flag) + check_shutdwon_voltage(); + + fRSOC_PRE = batt_info->fRSOC; + + // double check + if (bmu_sys_rw_kernel) + { + store_rc = bmu_read_data(BATT_CAPACITY); + if(store_rc != batt_info->sCaMAH) + { + bmu_write_data(BATT_CAPACITY,batt_info->sCaMAH); + bmu_write_data(BATT_FCC, gas_gauge->fcc_data); + //pr_err("init write sCaMAH %d,%d\n",batt_info->sCaMAH,store_rc); + } + } + + gas_gauge->bmu_init_ok = num_1; +} + +/***************************************************************************** +* Description: +* power down 8806 chip +* Parameters: +* None +* Return: +* None +*****************************************************************************/ +void bmu_power_down_chip(void) +{ + + afe_read_cell_temp(&batt_info->fCellTemp); + afe_read_cell_volt(&batt_info->fVolt); + afe_read_current(&batt_info->fCurr); + afe_read_car(&batt_info->fRC); + + if(oz8806_cell_num > num_1) + afe_register_write_byte(OZ8806_OP_CTRL,num_0x4c |SLEEP_OCV_EN); + else + afe_register_write_byte(OZ8806_OP_CTRL,SLEEP_MODE | SLEEP_OCV_EN); + + + if(parameter->config->debug){ + pr_err("eeee power down oz8806 \n"); + pr_err("eeee batt_info->fVolt is %d\n",(batt_info->fVolt * oz8806_cell_num)); + pr_err("eeee batt_info->fRSOC is %d\n",batt_info->fRSOC); + pr_err("eeee batt_info->sCaMAH is %d\n",batt_info->sCaMAH); + pr_err("eeee batt_info->fRC is %d\n",batt_info->fRC); + pr_err("eeee batt_info->fCurr is %d\n",batt_info->fCurr); + } + +} + +/***************************************************************************** +* Description: +* power up 8806 chip +* Parameters: +* None +* Return: +* None +*****************************************************************************/ +void bmu_wake_up_chip(void) +{ + uint8_t data; + int32_t ret; + int32_t value; + uint8_t discharge_flag = num_0; + uint8_t i; + int32_t sleep_time = 0; + int32_t car_wakeup = 0; + int8_t adapter_status = 0; + + pr_err("fCurr is %d\n",batt_info->fCurr); + + adapter_status = get_adapter_status(); + if ((batt_info->fCurr <= gas_gauge->discharge_current_th) || + (adapter_status == O2_CHARGER_BATTERY)) + { + discharge_flag = 1; + } + + pr_err("adapter_status: %d\n", adapter_status); + + bmu_sleep_flag = 1; + + time_sec = oz8806_get_system_boot_time(); + sleep_time = time_sec - previous_loop_timex; + pr_err("sleep time: %d s\n",sleep_time); + + oz8806_wakeup_full_power(); + + ret = afe_register_read_byte(OZ8806_OP_CTRL,&data);//wake up OZ8806 into FullPower mode + if((data & 0x40) || (ret < 0)) + { + pr_err("bmu_wake_up_chip read 0x09 ret is %d,i is %d \n",ret,data); + if(oz8806_cell_num > 1) + { + afe_register_write_byte(OZ8806_OP_CTRL,0x2c); + } + else + afe_register_write_byte(OZ8806_OP_CTRL,0x20); + pr_err("oz8806 wake up function\n"); + + } + + if(batt_info->fRSOC >=num_100) + { + if(batt_info->fRSOC >= num_100) batt_info->fRSOC = num_100; + if(batt_info->sCaMAH > (full_charge_data)) + { + pr_err("oz8806 wake up batt_info.sCaMAH big error is %d\n",batt_info->sCaMAH); + batt_info->sCaMAH = full_charge_data; + + } + } + + afe_read_current(&batt_info->fCurr); + afe_read_cell_volt(&batt_info->fVolt); + + pr_err("sCaMAH:%d,fRC:%d,fcurr:%d,volt:%d,sCtMAH:%d\n", + batt_info->sCaMAH,batt_info->fRC,batt_info->fCurr, + (batt_info->fVolt * oz8806_cell_num), + gas_gauge->sCtMAH); + + for(i = num_0;i< num_3;i++) + { + ret = afe_read_car(&car_wakeup); + if (ret >= 0) + { + if ((car_wakeup == 0) || ((!discharge_flag) && (car_wakeup < 0))) + { + car_error += 1; + pr_err("test fRC read: %d, %d\n",car_error, car_wakeup); //H7 Test Version + } + else + break; + } + } + + value = car_wakeup - batt_info->fRC; + //*******CAR zero reading Workaround****************************** + if (sleep_time < 0) sleep_time = 60; //force 60s + if (discharge_flag == 1) + sleep_time *= MAX_SUSPEND_CONSUME; //time * current / 3600 * 1000 + else + sleep_time *= MAX_SUSPEND_CHARGE; //time * current / 3600 * 1000 + + // 10% + if (ABS(car_wakeup, batt_info->fRC) > (10 * config_data->design_capacity / num_100)) //delta over 10% + { + if (((value * 1000) - sleep_time) < 0) //over max car range + { + value = (sleep_time / 1000); + pr_err("Ab CAR:%d,mod:%d\n",car_wakeup,value); + car_wakeup = value + batt_info->fRC; + afe_write_car(car_wakeup); + } + } + pr_err("CAR Prev:%d,CAR Now:%d\n",batt_info->fRC,car_wakeup); + //*******CAR zero reading Workaround****************************** + if(car_wakeup <= 0) + { + pr_err("fRC is %d\n",car_wakeup); + //oz8806_over_flow_prevent(); + gas_gauge->charge_fcc_update = num_0; + gas_gauge->discharge_fcc_update = num_0; + + if (car_wakeup < 0) //overflow check + { + if (batt_info->fVolt >= (config_data->charge_cv_voltage - 50)) + { + car_wakeup = gas_gauge->fcc_data -num_1; + } + else + { + if (batt_info->fRSOC > 0) + car_wakeup = batt_info->fRSOC * gas_gauge->fcc_data / num_100 - num_1; + else + car_wakeup = batt_info->sCaMAH; + } + afe_write_car(car_wakeup); + batt_info->fRC = car_wakeup; + batt_info->fRCPrev = batt_info->fRC; + } + + if(discharge_flag) + { + check_shutdwon_voltage(); + value = calculate_soc_result(); + if(value < batt_info->fRSOC) + { + batt_info->fRSOC = value; + batt_info->sCaMAH = batt_info->fRSOC * gas_gauge->fcc_data / 100; + batt_info->fRC = batt_info->sCaMAH; + batt_info->fRCPrev = batt_info->fRC; + afe_write_car(batt_info->fRC); + } + + if(batt_info->fRSOC <= 0) + { + if((batt_info->fVolt <= config_data->discharge_end_voltage)) + { + discharge_end_process(); + } + //wait voltage + else + { + batt_info->fRSOC = 1; + batt_info->sCaMAH = gas_gauge->fcc_data / num_100 ; + gas_gauge->discharge_end = num_0; + } + } + return; + } + } + + if ((discharge_flag) && (car_wakeup > batt_info->fRC)) + { + pr_err("it seems error 1\n"); + value = car_wakeup - batt_info->fRC; + car_wakeup = batt_info->fRC - value; + afe_write_car(car_wakeup); + } + if ((!discharge_flag) && (car_wakeup < batt_info->fRC)) + { + pr_err("it seems error 2\n"); + value = batt_info->fRC - car_wakeup; + car_wakeup = batt_info->fRC + value; + afe_write_car(car_wakeup); + } + + bmu_dbg("tttt final wakeup car is %d\n",car_wakeup); +} + + +/***************************************************************************** +* Description: +* check_board_offset +* Parameters: +* None +* Return: +* None +*****************************************************************************/ +static void check_board_offset(void) +{ + int32_t data; + int32_t ret; + int32_t offset; + int32_t ret2; + + ret2 = afe_read_board_offset(&data); + + if(config_data->board_offset != data && config_data->board_offset != num_0) + { + afe_write_board_offset(config_data->board_offset); + return; + } + + ret = bmu_read_data(BATT_OFFSET); + + + //pr_err("AAAA board_offset is %d\n",data); + + if(ret < num_0) + { + + if((data > num_10) || (data <= num_0)) + afe_write_board_offset(7); + + if(ret2 >= num_0) + { + if((data < num_10) && (data > num_0) && (data != num_0)) + { + ret = bmu_write_data(BATT_OFFSET,data); + + if(ret num_2) || ((offset - data) < -num_2)) + afe_write_board_offset(offset); + } + + afe_read_board_offset(&data); + if((data > num_10) || (data <= num_0)) + afe_write_board_offset(num_7); + + afe_read_board_offset(&data); + pr_err("AAAA board_offset is %dmA\n",data); +} + +/***************************************************************************** +* Description: +* bmu polling loop +* Parameters: +* None +* Return: +* None +*****************************************************************************/ +void bmu_polling_loop(void) +{ + int32_t data; + + int32_t ret; + uint8_t i; + static uint8_t error_times = 0; +#if (FORCE_OTP_MAPPING) + uint32_t force_otp_time = 0; +#endif + int8_t adapter_status = 0; + uint8_t retry = 0; + uint8_t val = 0; + if(is_battery_exchanged()){ //battery was exchanged, oz8806 in start-up mode + gas_gauge->bmu_init_ok = 0; + batt_info->i2c_error_times = 0; + pr_err("battery was exchanged, init SOC again\n"); + +retry_wakeup: + //wake up this stupid chip + oz8806_wakeup_full_power(); + msleep(10) ; + ret = afe_register_read_byte(OZ8806_OP_CTRL,&val); + if((val & 0x40) || (ret < 0)) + { + pr_err("bmu_wake_up_chip read 0x09 ret is %d,i is %d \n",ret,val); + retry++; + + if(retry>10){ + pr_err("fail wakeup ic"); + } + goto retry_wakeup; + } + + retry_times = 0; + calculate_times = 0; + times = 0; + wait_ocv_flag = 0; + wait_ocv_flag_fun(); + } + + bmu_dbg("-----------------------bmu_polling_loop start------------------\n"); + + if(!(gas_gauge->bmu_init_ok)) + { + if(!wait_ocv_flag) + wait_ocv_flag_fun(); + else + bmu_wait_ready(); + + if(gas_gauge->bmu_init_ok) + check_board_offset(); + + goto end; + } + + batt_info->fRCPrev = batt_info->fRC; + + afe_read_cell_temp(&batt_info->fCellTemp); + afe_read_cell_volt(&batt_info->fVolt); + afe_read_current(&batt_info->fCurr); + + //be careful for large current + //and wake up condition + ret = afe_read_car(&data); + if(parameter->config->debug) { + if (data == 0) car_error++; + pr_err("CAR is %d, %d\n",data, car_error); + } + + if((ret >= 0) && (data > 0)) + { + // for big current charge + // 10% + if (ABS(batt_info->fRCPrev, data) < (10 * config_data->design_capacity / num_100)) + { + batt_info->fRC = data; + error_times = 0; + } + else + { + error_times++; + if(error_times > 3) + { + pr_err("CAR error_times is %d\n",error_times); + error_times = 0; + afe_write_car(batt_info->sCaMAH); + batt_info->fRCPrev = batt_info->sCaMAH; + batt_info->fRC = batt_info->sCaMAH; + } + } + } + + bmu_dbg("first sCaMAH:%d,fRC:%d,fRCPrev:%d,fcurr:%d,volt:%d\n", + batt_info->sCaMAH,batt_info->fRC,batt_info->fRCPrev, + batt_info->fCurr,(batt_info->fVolt * oz8806_cell_num)); + + //back sCaMAH + //H7====LOW VOLTAGE CHARGE PREVENT====== + if ((batt_info->fVolt < config_data->discharge_end_voltage) && (batt_info->fCurr > 0)) //charge and voltage < 3300 + { + pr_err("Low voltage %d charge current %d detected\n",batt_info->fVolt,batt_info->fCurr); + if (batt_info->fRC > batt_info->fRCPrev) //CAR increased + { + pr_err("Low voltage fRC limit triggered %d\n",batt_info->fRCPrev); + batt_info->fRC = batt_info->fRCPrev; //Limit CAR as previous + afe_write_car(batt_info->fRC); //write back CAR + } + } + //H7====LOW VOLTAGE CHARGE PREVENT====== + + + gas_gauge->sCtMAH += batt_info->fRC - batt_info->fRCPrev; + gas_gauge->discharge_sCtMAH += batt_info->fRCPrev - batt_info->fRC; + + if(gas_gauge->sCtMAH < num_0) gas_gauge->sCtMAH = num_0; + if(gas_gauge->discharge_sCtMAH < num_0) gas_gauge->discharge_sCtMAH = num_0; + + //bmu_call(); + + adapter_status = get_adapter_status(); + if ((batt_info->fCurr <= gas_gauge->discharge_current_th) || + (adapter_status == O2_CHARGER_BATTERY)) + discharge_process(); + else + charge_process(); + + bmu_dbg("second sCaMAH:%d,fRC:%d,fRCPrev:%d,fcurr:%d,volt:%d\n", + batt_info->sCaMAH,batt_info->fRC,batt_info->fRCPrev, + batt_info->fCurr,(batt_info->fVolt * oz8806_cell_num)); + + if(gas_gauge->charge_end) + { + if(!charge_end_flag) + { + pr_err("enter 8806 charge end\n"); + charge_end_flag = num_1; + charge_end_process(); + } + + } + else + { + charge_end_flag = num_0; + } + + + + if(gas_gauge->discharge_end) + { + if(!discharge_end_flag) + { + discharge_end_flag = num_1; + discharge_end_process(); + } + + } + else + { + discharge_end_flag = num_0; + } + + oz8806_over_flow_prevent(); + + /* + //very dangerous + if(batt_info->fVolt <= (config_data->discharge_end_voltage - num_100)) + { + ret = afe_read_cell_volt(&batt_info->fVolt); + if((ret >=0) && (batt_info->fVolt > 2500)) + discharge_end_process(); + } + */ + + + //gas_gauge->bmu_tick++; + previous_loop_timex = time_sec; + time_sec = oz8806_get_system_boot_time(); + bmu_dbg("----------------------------------------------------\n" + "VERSION: %s\n" + "TABLEVERSION: %s\n" + "battery_ok: %d,time_x: %d\n" + "chg_fcc_update: %d, disg_fcc_update: %d\n" + "fVolt: %d fCurr: %d fCellTemp: %d fRSOC: %d\n" + "sCaMAH: %d, sCtMAH1: %d, sCtMAH2: %d\n" + "fcc: %d, fRC: %d\n" + "i2c_error_times: %d\n" + "charge_end: %d, discharge_end: %d\n" + "adapter_status: %d\n" + "----------------------------------------------------\n", + VERSION, get_table_version(),batt_info->Battery_ok,time_sec, + gas_gauge->charge_fcc_update,gas_gauge->discharge_fcc_update, + (batt_info->fVolt * oz8806_cell_num),batt_info->fCurr,batt_info->fCellTemp,batt_info->fRSOC, + batt_info->sCaMAH,gas_gauge->sCtMAH,gas_gauge->discharge_sCtMAH, + gas_gauge->fcc_data,batt_info->fRC, + batt_info->i2c_error_times, + gas_gauge->charge_end,gas_gauge->discharge_end, + adapter_status); + + if(batt_info->sCaMAH > (full_charge_data)) + { + pr_err("big error sCaMAH is %d\n",batt_info->sCaMAH); + batt_info->sCaMAH = full_charge_data; + } + + if(batt_info->sCaMAH < (gas_gauge->fcc_data / 100 - 1)) + { + //pr_err("big error sCaMAH is %d\n",batt_info->sCaMAH); + batt_info->sCaMAH = gas_gauge->fcc_data / 100 - 1; + } + + /* + if(gas_gauge->fcc_data > (config_data->design_capacity *FCC_UPPER_LIMIT / 100)) + { + gas_gauge->fcc_data= config_data->design_capacity * FCC_UPPER_LIMIT / 100 ; + bmu_write_data(BATT_FCC,gas_gauge->fcc_data); + + pr_err("fcc error is %d\n",gas_gauge->fcc_data); + + } + if((gas_gauge->fcc_data <= 0) || (gas_gauge->fcc_data < (config_data->design_capacity * FCC_LOWER_LIMIT / 100))) + { + gas_gauge->fcc_data = config_data->design_capacity * FCC_LOWER_LIMIT /100; + bmu_write_data(BATT_FCC,gas_gauge->fcc_data); + + pr_err("fcc error is %d\n",gas_gauge->fcc_data); + + } + */ + + gas_gauge->fcc_data= config_data->design_capacity; + + if (bmu_sys_rw_kernel) + { + data = bmu_read_data(BATT_CAPACITY); + //bmu_dbg("read from RAM batt_info->sCaMAH is %d\n",data); + if(data >= num_0) + { + if(fRSOC_PRE != batt_info->fRSOC) + { + fRSOC_PRE = batt_info->fRSOC; + bmu_write_data(BATT_CAPACITY,batt_info->sCaMAH); + // bmu_dbg("o2 back batt_info->sCaMAH num_1 is %d\n",batt_info->sCaMAH); + //return; + goto end; + + } + + if(((batt_info->sCaMAH - data)> (gas_gauge->fcc_data/200))||((data - batt_info->sCaMAH)> (gas_gauge->fcc_data/200))){ + bmu_write_data(BATT_CAPACITY,batt_info->sCaMAH); + // bmu_dbg("o2 back batt_info->sCaMAH 2 is %d\n",batt_info->sCaMAH); + } + } + else bmu_write_data(BATT_CAPACITY,batt_info->sCaMAH); + } + else + { + if(fRSOC_PRE != batt_info->fRSOC) + { + fRSOC_PRE = batt_info->fRSOC; + //bmu_dbg("o2 back batt_info->sCaMAH num_1 is %d\n",batt_info->sCaMAH); + goto end; + } + } + + //wake up OZ8806 into FullPower mode + ret = afe_register_read_byte(OZ8806_OP_CTRL,&i); + batt_info->Battery_ok = i & BI_STATUS; + if(ret < 0) + batt_info->Battery_ok = 0; + + if((i & num_0x40) || (ret < num_0)) + { + bmu_dbg("bmu_polling_loop read 0x09 ret is %d,i is %d \n",ret,i); + if(oz8806_cell_num > 1) + { + afe_register_write_byte(OZ8806_OP_CTRL,num_0x2c); + } + else + afe_register_write_byte(OZ8806_OP_CTRL,num_0x20); + //pr_err("oz8806 wake up function\n"); + + } + + ret = afe_read_board_offset(&data); + if (ret >= 0) + { + if (config_data->board_offset != 0) + { + //if (data != config_data->board_offset) + if(ABS(data, config_data->board_offset) > 3) + { + afe_write_board_offset(config_data->board_offset); + pr_err("oz8806 board offset error1 is %d \n",data); + } + } + else + { + if((data > 10) || (data <= 0)) + { + pr_err("oz8806 board offset error2 is %d \n",data); + afe_write_board_offset(7); + } + + } + } + + + bmu_dbg("test data is %d\n",batt_info->sCaMAH); + + /* + + data = bmu_read_data(BATT_FCC); + + if(data != gas_gauge->fcc_data) + { + bmu_write_data(BATT_FCC,gas_gauge->fcc_data); + pr_err("test %d\n",gas_gauge->fcc_data); + } + + */ + +end: + bmu_dbg("-----------------------bmu_polling_loop end--------------------\n"); +} + +/***************************************************************************** +* Description: +* prevent oz8806 over flow +* Parameters: +* None +* Return: +* None +*****************************************************************************/ +static void oz8806_over_flow_prevent(void) +{ + int32_t ret; + int32_t data; + + if((batt_info->fRSOC > num_0) && gas_gauge->discharge_end) + gas_gauge->discharge_end = num_0; + + if((batt_info->fRSOC < num_100) && gas_gauge->charge_end) + gas_gauge->charge_end = num_0; + + if(batt_info->fRC< num_0) + { + if(batt_info->fVolt >= (config_data->charge_cv_voltage - 200)) + { + batt_info->fRC = gas_gauge->fcc_data -num_1; + } + else + { + if(batt_info->fRSOC > 0) + batt_info->fRC = batt_info->fRSOC * gas_gauge->fcc_data / num_100 - num_1; + else + batt_info->fRC = batt_info->sCaMAH; + } + + afe_write_car(batt_info->fRC); + batt_info->fRCPrev = batt_info->fRC; + } + + /* + ret = oz8806_read_word(OZ8806_OP_CAR); + + if(ret >= num_0) + { + ret = (int16_t)ret; + if(ret >= (num_32768 - num_10 * config_data->fRsense)) + { + if(parameter->config->debug)pr_err("yyyy CAR WILL UP OVER %d\n",ret); + ret = 32768 - 15 * config_data->fRsense; + oz8806_write_word(OZ8806_OP_CAR,(int16_t)ret); + afe_read_car(&batt_info->fRC); + batt_info->fRCPrev = batt_info->fRC; + + } + else if(ret <= (num_10 * config_data->fRsense)) + { + if(parameter->config->debug)pr_err("yyyy CAR WILL DOWN OVER %d\n",ret); + ret = num_15 * config_data->fRsense; + oz8806_write_word(OZ8806_OP_CAR,(int16_t)ret); + afe_read_car(&batt_info->fRC); + batt_info->fRCPrev = batt_info->fRC; + } + + + } + */ + + ret = afe_read_car(&data); + if(ret<0) + return; + + if(data < 5) + { + afe_write_car(batt_info->sCaMAH); + batt_info->fRCPrev = batt_info->sCaMAH; + batt_info->fRC = batt_info->sCaMAH; + bmu_dbg("dddd car down is %d\n",data); + } + else if(data > (32768 * parameter->config->dbCARLSB * 1000 / config_data->fRsense -5)) + { + afe_write_car(batt_info->sCaMAH); + batt_info->fRCPrev = batt_info->sCaMAH; + batt_info->fRC = batt_info->sCaMAH; + bmu_dbg("dddd car up is %d\n",data); + } + + if(ABS(batt_info->sCaMAH, data) > one_percent_rc) + { + if((batt_info->sCaMAH < gas_gauge->overflow_data ) && (batt_info->sCaMAH > 0)) + { + afe_write_car(batt_info->sCaMAH); + batt_info->fRCPrev = batt_info->sCaMAH; + batt_info->fRC = batt_info->sCaMAH; + if(parameter->config->debug){ + pr_err("dddd write car batt_info->fRCPrev is %d\n",batt_info->fRCPrev); + pr_err("dddd write car batt_info->fRC is %d\n",batt_info->fRC); + pr_err("dddd write car batt_info->sCaMAH is %d\n",batt_info->sCaMAH); + } + } + } + + + if(batt_info->fRC > (full_charge_data)) + { + pr_err("more fRC %d\n",batt_info->fRC); + batt_info->fRC = full_charge_data; + batt_info->fRCPrev = batt_info->fRC; + afe_write_car(batt_info->fRC); + } +} + + + +/***************************************************************************** +* Description: +* charge fcc update process +* Parameters: +* None +* Return: +* None +*****************************************************************************/ +void charge_end_process(void) +{ + //FCC UPdate + + /* + if(gas_gauge->charge_fcc_update) + { + if(batt_info->fCurr < config_data->charge_end_current) + gas_gauge->fcc_data = gas_gauge->sCtMAH; + bmu_write_data(BATT_FCC,gas_gauge->fcc_data); + + pr_err("charge1 fcc update is %d\n",gas_gauge->fcc_data); + + } + + if(gas_gauge->fcc_data > (config_data->design_capacity *FCC_UPPER_LIMIT / 100)) + { + gas_gauge->fcc_data= config_data->design_capacity * FCC_UPPER_LIMIT / 100 ; + bmu_write_data(BATT_FCC,gas_gauge->fcc_data); + + pr_err("charge2 fcc update is %d\n",gas_gauge->fcc_data); + + } + if((gas_gauge->fcc_data <= 0) || (gas_gauge->fcc_data < (config_data->design_capacity * FCC_LOWER_LIMIT / 100))) + { + gas_gauge->fcc_data = config_data->design_capacity * FCC_LOWER_LIMIT / 100; + bmu_write_data(BATT_FCC,gas_gauge->fcc_data); + + pr_err("charge3 fcc update is %d\n",gas_gauge->fcc_data); + + } + */ + + gas_gauge->fcc_data = config_data->design_capacity; + batt_info->sCaMAH = full_charge_data;; + + if (bmu_sys_rw_kernel) + bmu_write_data(BATT_CAPACITY,batt_info->sCaMAH); + + afe_write_car(batt_info->sCaMAH); + + if(gas_gauge->ocv_flag) + bmu_write_data(OCV_FLAG,0); + + pr_err("yyyy end charge \n"); + batt_info->fRSOC = num_100; + gas_gauge->charge_end = num_1; + charge_end_flag = num_1; + //charger_finish = 0; + gas_gauge->charge_fcc_update = 1; + gas_gauge->discharge_fcc_update = 1; + gas_gauge->discharge_sCtMAH = 0; + power_on_flag = 0; + +} + +/***************************************************************************** +* Description: +* discharge fcc update process +* Parameters: +* None +* Return: +* None +*****************************************************************************/ +void discharge_end_process(void) +{ + //int32_t voltage_end = config_data->discharge_end_voltage; + + //FCC UPdate + /* + if(gas_gauge->discharge_fcc_update) + { + gas_gauge->fcc_data = gas_gauge->discharge_sCtMAH; + bmu_write_data(BATT_FCC,gas_gauge->fcc_data); + pr_err("discharge1 fcc update is %d\n",gas_gauge->fcc_data); + + } + + if(gas_gauge->fcc_data > (config_data->design_capacity *FCC_UPPER_LIMIT / 100)) + { + gas_gauge->fcc_data= config_data->design_capacity * FCC_UPPER_LIMIT / 100 ; + bmu_write_data(BATT_FCC,gas_gauge->fcc_data); + pr_err("discharge2 fcc update is %d\n",gas_gauge->fcc_data); + } + if((gas_gauge->fcc_data <= 0) || (gas_gauge->fcc_data < (config_data->design_capacity * FCC_LOWER_LIMIT / 100))) + { + gas_gauge->fcc_data = config_data->design_capacity * FCC_LOWER_LIMIT / 100; + bmu_write_data(BATT_FCC,gas_gauge->fcc_data); + pr_err("discharge3 fcc update is %d\n",gas_gauge->fcc_data); + } + */ + gas_gauge->fcc_data = config_data->design_capacity; + if(gas_gauge->ocv_flag) + bmu_write_data(OCV_FLAG,0); + + batt_info->sCaMAH = gas_gauge->fcc_data / 100 - 1; + + if (bmu_sys_rw_kernel) + bmu_write_data(BATT_CAPACITY,batt_info->sCaMAH); + + afe_write_car(batt_info->sCaMAH); + batt_info->fRCPrev = batt_info->sCaMAH; + + + pr_err("yyyy end discharge \n"); + batt_info->fRSOC = num_0; + gas_gauge->discharge_end = num_1; + gas_gauge->discharge_fcc_update = 1; + gas_gauge->charge_fcc_update = 1; + gas_gauge->sCtMAH = num_0; + +} + + + +/***************************************************************************** +* Description: +* below is linux file operation +* Parameters: +* description for each argument, new argument starts at new line +* Return: +* what does this function returned? +*****************************************************************************/ +#if 0 +static int bmu_check_file(char * address) +{ + long fd = sys_open(address,O_RDONLY,0644); + + if(fd < num_0) + { + //bmu_dbg(" bmu check file fail %s\n",address); + return -num_1; + } + sys_close(fd); + return (num_0); +} + + +static int bmu_read_data(char * address) +{ + char value[4]; + int* p = (int *)value; + long fd = sys_open(address,O_RDONLY,0644); + + if(fd < num_0) + { + bmu_dbg(" bmu read open file fail %s, return %ld\n",address, fd); + return fd; + } + + sys_read(fd,(char __user *)value,4); + + sys_close(fd); + + return (*p); +} + +static int bmu_write_data(char * address,int data) +{ + char value[4]; + int* p = (int *)value; + long fd = sys_open(address,O_CREAT | O_RDWR, 0644); + + if(fd < num_0) + { + bmu_dbg("bmu wirte open file fail %s failed, return %ld\n",address, fd); + return fd; + } + *p = data; + sys_write(fd, (const char __user *)value, 4); + + sys_close(fd); + return num_0; +} + +#else +static int bmu_read_data(char * address) +{ + return -1; +#if 0 + struct file *fp = NULL; + mm_segment_t fs; + loff_t pos = 0; + char buf_r[5]; + int ret = 0; + int val = 0; + + //pr_err("%s\n", __func__); + + fp = filp_open(address, O_RDONLY, 0644); + if (IS_ERR(fp)) + { + pr_err(" %s: open file fail %s\n", __func__, address); + return -1; + } + + fs = get_fs(); + set_fs(KERNEL_DS); + + pos = 0; + ret = vfs_read(fp, buf_r, sizeof(buf_r), &pos); + if (ret < 0) + pr_err(" %s: read file fail %s\n", __func__, address); + + buf_r[4] = '\0'; + bmu_dbg("%s: read: %s\n", __func__, buf_r); + + ret = kstrtoint(buf_r, 10, &val); + if (ret < 0) + pr_err(" %s: fail to get int from %s\n", __func__, address); + + set_fs(fs); + + filp_close(fp, NULL); + + if (ret < 0) + return ret; + + return val; +#endif +} + +static int bmu_write_data(char * address,int data) +{ + return -1; +#if 0 + struct file *fp = NULL; + mm_segment_t fs; + loff_t pos = 0; + char buf[5]; + char buf_r[5]; + int ret = 0; + int val = 0; + + ret = sprintf(buf, "%d", data); + + //pr_err("%s\n", __func__); + + fp = filp_open(address, O_RDWR | O_CREAT, 0644); + if (IS_ERR(fp)) + { + pr_err(" %s: open file fail %s\n", __func__, address); + return -1; + } + + fs = get_fs(); + set_fs(KERNEL_DS); + + pos = 0; + ret = vfs_write(fp, buf, sizeof(buf), &pos); + if (ret < 0) + pr_err(" %s: write file fail %s\n", __func__, address); + + else if (!strcmp(address, BATT_CAPACITY)) + gas_gauge->stored_capacity = data; + + if(config_data->debug) + { + pos = 0; + ret = vfs_read(fp, buf_r, sizeof(buf_r), &pos); + if (ret < 0) + pr_err(" %s: read file fail %s\n", __func__, address); + + bmu_dbg("%s: read: %s\n", __func__, buf_r); + + ret = kstrtoint(buf_r, 10, &val); + if (ret < 0) + pr_err(" %s: fail to get int from %s\n", __func__, address); + } + + set_fs(fs); + + filp_close(fp, NULL); + + return ret; +#endif +} +#if 0 +static int bmu_check_file(char * address) +{ + struct file *fp = NULL; + + fp = filp_open(address, O_RDONLY, 0644); + if (IS_ERR(fp)) + { + pr_err(" %s: open file fail %s\n", __func__, address); + return -1; + } + return 0; +} +#endif +#endif + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +/**************************************************************************** + * Description: + * oz8806_write_byte_pec + * Parameters: + * //addr: oz8806 slave address + * index: oz8806 operation register + * data: write data + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +#if 0 +static int32_t oz8806_write_byte_pec(uint8_t addr,uint8_t index, uint8_t data) +{ + int32_t ret; + + uint8_t pec_data = num_0; + uint16_t temp = num_0; + pec_data =pec_calculate(pec_data,addr); + pec_data =pec_calculate(pec_data,index); + pec_data =pec_calculate(pec_data,data); + temp = pec_data; + temp <<= 8; + temp |= data; + ret = i2c_smbus_write_word_data(parameter->client, index,temp); + return ret; +} +#endif + + + +/**************************************************************************** + * Description: + * read oz8806 operation register + * Parameters: + * index: oz8806 operation register + * buf: pointer to buffer to store read data + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_read_byte(uint8_t index) +{ + int32_t ret; + uint8_t pec_data = num_0; + uint8_t temp; + + + if(num_0) + { + ret = i2c_smbus_read_word_data(parameter->client, index); + if(ret < num_0 ) return ret; + pec_data =pec_calculate(pec_data,0x5e); + pec_data =pec_calculate(pec_data,index); + pec_data =pec_calculate(pec_data,0x5f); + temp = (uint8_t)(ret & 0xff); + pec_data =pec_calculate(pec_data,temp); + temp = (uint8_t)(ret >> 8); + + if(pec_data != temp) + { + pr_err("33333333333333333 oz8806_read_byte\n"); + pr_err("33333333333333333 pec_data is %d\n",pec_data); + pr_err("33333333333333333 temp is %d\n",temp); + return -num_1; + } + + return ret; + } + else + { + ret = i2c_smbus_read_byte_data(parameter->client, index); + return ret; + } +} + + +/**************************************************************************** + * Description: + * write oz8806 operation register + * Parameters: + * index: oz8806 operation register + * data: write data + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_write_byte(uint8_t index, uint8_t data) +{ + int32_t ret; + uint8_t pec_data = num_0; + uint16_t temp = num_0; + + if(oz8806_pec_check) + { + pec_data =pec_calculate(pec_data,0x5e); + pec_data =pec_calculate(pec_data,index); + pec_data =pec_calculate(pec_data,data); + temp = pec_data; + temp <<= 8; + temp |= data; + ret = i2c_smbus_write_word_data(parameter->client, index,temp); + return ret; + } + else + { + ret = i2c_smbus_write_byte_data(parameter->client, index,data); + return ret; + } +} + +/**************************************************************************** + * Description: + * read oz8806 operation register word + * Parameters: + * index: oz8806 operation register + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_read_word(uint8_t index) +{ + int32_t ret = num_0; + int32_t ret1 = num_0; + uint8_t temp; + uint8_t pec_data = num_0; + + if(num_0) + { + ret = i2c_smbus_read_word_data(parameter->client, index); + if(ret < num_0) return ret; + pec_data =pec_calculate(pec_data,0x5e); + pec_data =pec_calculate(pec_data,index); + pec_data =pec_calculate(pec_data,0x5f); + temp = (uint8_t)(ret & 0xff); + pec_data =pec_calculate(pec_data,temp); + temp = (uint8_t)(ret >> 8); + + if(pec_data != temp) + { + pr_err("index 0x%02x\n",index); + pr_err("0x%02x\n",(uint8_t)(ret & 0xff)); + pr_err("33333333333333333 oz8806_read_word num_1\n"); + pr_err("33333333333333333 pec_data is 0x%02x\n",pec_data); + pr_err("33333333333333333 temp is 0x%02x\n",temp); + + pr_err("33333333333333333 ret is 0x%02x\n",ret); + return -num_1; + } + + ret1 = i2c_smbus_read_word_data(parameter->client, (index + num_1)); + if(ret1 < num_0) return ret1; + + pec_data = num_0; + pec_data =pec_calculate(pec_data,0x5e); + pec_data =pec_calculate(pec_data,(index +num_1)); + pec_data =pec_calculate(pec_data,0x5f); + temp = (uint8_t)(ret1 & 0xff); + pec_data =pec_calculate(pec_data,temp); + temp = (uint8_t)(ret1 >> 8); + + if(pec_data != temp) + { + pr_err("33333333333333333 oz8806_read_word 2\n"); + pr_err("33333333333333333 pec_data is %d\n",pec_data); + pr_err("33333333333333333 temp is %d\n",temp); + return -num_1; + } + + ret1 <<= 8; + ret1 |= (uint8_t)(0xff & ret); + return ret1; + } + else + { + ret = i2c_smbus_read_word_data(parameter->client, index); + return ret; + } +} + +/**************************************************************************** + * Description: + * write oz8806 operation register + * Parameters: + * index: oz8806 operation register + * data: write data + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_write_word( uint8_t index, uint16_t data) +{ + int32_t ret; + uint8_t pec_data = num_0; + uint16_t temp = num_0; + + + if(oz8806_pec_check) + { + + pec_data =pec_calculate(pec_data,0x5e); + pec_data =pec_calculate(pec_data,index); + pec_data =pec_calculate(pec_data,(uint8_t)data); + temp = pec_data; + temp <<= 8; + temp |= (uint8_t)data; + ret = i2c_smbus_write_word_data(parameter->client, index,temp); + + if(ret < num_0) return ret; + pec_data = num_0; + + pec_data =pec_calculate(pec_data,0x5e); + pec_data =pec_calculate(pec_data,(index +num_1)); + pec_data =pec_calculate(pec_data,(uint8_t)(data>>8)); + temp = pec_data; + temp <<= 8; + temp |= (uint8_t)(data >> 8); + ret = i2c_smbus_write_word_data(parameter->client, (index +num_1),temp); + + return ret; + } + else + { + ret = i2c_smbus_write_word_data(parameter->client, index,data); + return ret; + } +} + +/**************************************************************************** + * Description: + * read oz8806 cell voltage + * Parameters: + * voltage: cell voltage in mV, range from -5120mv to +5120mv + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_cell_voltage_read(int32_t *voltage) +{ + int32_t ret; + int32_t data; + + ret = oz8806_read_word(OZ8806_OP_CELL_VOLT); + + if (ret < num_0) return ret; + + data = ret & 0xFFFF; + data = (int16_t)data / 16; // >> 4 and keep sign bit + + data = data * parameter->config->fVoltLSB; //fVoltLSB = 250 (2.5 mV) + data = data / num_100; //fVoltLSB = 250 (2.5 mV) + + if (data > 5117 || data < 0) + { + pr_err("%s:data: %d, reg:%x\n", __func__, data, ret); + return -1; + } + batt_info->i2c_error_times = 0; + *voltage = data; + + return ret; +} + +/**************************************************************************** + * Description: + * read oz8806 cell OCV(open circuit voltage) + * Parameters: + * voltage: voltage in mV, range from -5120mv to +5120mv with 2.5mV LSB + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_ocv_voltage_read(int32_t *voltage) +{ + int32_t ret; + int32_t data; + + ret = oz8806_read_word(OZ8806_OP_OCV_LOW); + if (ret < num_0) return ret; + + data = ret & 0xFFFF; + data = (int16_t)data / 16; // >> 4 and keep sign bit + + data = data * parameter->config->fVoltLSB; //fVoltLSB = 250 (2.5 mV) + data = data / num_100; //fVoltLSB = 250 (2.5 mV) + + if (data > 5117 || data < 0) + { + pr_err("%s:data: %d, reg:%x\n", __func__, data, ret); + return -1; + } + + *voltage = data; + + return ret; +} + +/**************************************************************************** + * Description: + * read oz8806 current + * Parameters: + * current: in mA, range is +/-64mv / Rsense with 7.8uv LSB / Rsense + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_current_read(int32_t *data) + +{ + int32_t ret; + int32_t temp; + + ret = oz8806_read_word(OZ8806_OP_CURRENT); + + if (ret < num_0) return ret; + + temp = ret & 0xFFFF; + temp = (int16_t)temp * parameter->config->dbCurrLSB; //dbCurrLSB = 391 (3.90625 mA) + temp = (temp * 10 / parameter->config->fRsense); + temp /= 4; + + batt_info->i2c_error_times = 0; + *data = temp; + return ret; +} + +/**************************************************************************** + * Description: + * read oz8806 temp + * Parameters: + * voltage: voltage value in mV, range is +/- 5120mV with 2.5mV LSB + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +int32_t oz8806_temp_read(int32_t *voltage) +{ + int32_t ret; + int32_t data; + + ret = oz8806_read_word(OZ8806_OP_CELL_TEMP); + if (ret < num_0) return ret; + + //pr_err("1111111111111 regeister is 0x%02x\n",ret); + + data = ret & 0xFFFF; + data = (int16_t)data / 16; // >> 4 and keep sign bit + + data = data * parameter->config->fVoltLSB; //fVoltLSB = 250 (2.5 mV) + data = data / num_100; //fVoltLSB = 250 (2.5 mV) + + if (data > 5117 || data < 0) + { + pr_err("%s:data: %d, reg:%x\n", __func__, data, ret); + return -1; + } + + *voltage = data; + + //pr_err("1111111111111 voltage is %d\n",*voltage); + + return ret; +} + +/**************************************************************************** + * Description: + * read oz8806 CAR + * Parameters: + * car: in mAHr, range is +/- 163840 uvHr/ Rsense with 5 uvHr LSB / Rsense + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_car_read(int32_t *car) +{ + int32_t ret; + int32_t data; + + + ret = oz8806_read_word(OZ8806_OP_CAR); + if (ret < num_0) return ret; + + + data = (int16_t)ret; + data = data * parameter->config->dbCARLSB; + data = data * 1000 / parameter->config->fRsense; + + batt_info->i2c_error_times = 0; + *car = (int16_t)data; + return ret; +} + + +/**************************************************************************** + * Description: + * write oz8806 CAR + * Parameters: + * data: in mAHr, range is +/- 163840 uvHr/ Rsense with 5 uvHr LSB / Rsense + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_car_write(int32_t data) +{ + int32_t temp; + int32_t ret; + + temp = data; + temp = (temp * parameter->config->fRsense) / parameter->config->dbCARLSB; //transfer to CAR + temp /= 1000; + ret = oz8806_write_word(OZ8806_OP_CAR,(uint16_t)temp); + + return ret; +} + +/**************************************************************************** + * Description: + * read oz8806 board offset + * Parameters: + * data: in mA, +/- 8mV / Rsense with 7.8uV / Rsense + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_board_offset_read(int32_t *data) +{ + int32_t ret; + int32_t temp; + + + ret = oz8806_read_word(OZ8806_OP_BOARD_OFFSET); + if (ret < num_0) return ret; + + + temp = (int16_t)ret; + temp = temp & 0x7ff; + if(temp & 0x0400)// if bit[10] is 1, it's negative + temp = temp |0xfffffc00; + temp = temp * 78; + temp = temp * 100/ config_data->fRsense; + + *data = (int16_t)temp; + return ret; +} + +/**************************************************************************** + * Description: + * write oz8806 board offset + * Parameters: + * data: the data will be wrriten + * Return: + * see I2C_STATUS_XXX define + ****************************************************************************/ +static int32_t oz8806_board_offset_write(int32_t data) +{ + int32_t ret; + int32_t over_data; + + + + if(data > num_0){ + data = data * config_data->fRsense * num_10 / 78; + data /= 1000; + if(data > 0x3ff)data = 0x3ff; + ret = oz8806_write_word(OZ8806_OP_BOARD_OFFSET,(uint16_t)data); + } + else if(data < num_0){ + over_data = (-1024 * 78 * 1000) / (config_data->fRsense * num_10); + if(data < over_data) + data = over_data; + data = data * config_data->fRsense * num_10 / 78; + data /= 1000; + data = (data & 0x07ff) | 0x0400; + ret = oz8806_write_word(OZ8806_OP_BOARD_OFFSET,(uint16_t)data); + } + else + ret = oz8806_write_word(OZ8806_OP_BOARD_OFFSET,num_0); + + return ret; +} + + +/***************************************************************************** + * Description: + * wrapper function for operation register byte reading + * Parameters: + * index: register index to be read + * *dat: buffer to store data read back + * Return: + * I2C_STATUS_OK if read success, else inidcate error + *****************************************************************************/ +static int32_t afe_register_read_byte(uint8_t index, uint8_t *dat) +{ + int32_t ret; + uint8_t i; + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_read_byte(index); + if(ret >=num_0) break; + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + + *dat = (uint8_t)ret; + + return ret; +} + + +/***************************************************************************** + * Description: + * wrapper function for operation register byte writing + * Parameters: + * index: register index to be read + * dat: write data + * Return: + * see I2C_STATUS_XXX define + *****************************************************************************/ +static int32_t afe_register_write_byte(uint8_t index, uint8_t dat) +{ + int32_t ret; + uint8_t i; + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_write_byte(index, dat); + if(ret >= num_0) break; + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + + return ret; +} + + +/***************************************************************************** + * Description: + * wrapper function for operation register word reading + * Parameters: + * index: register index to be read + * *dat: buffer to store data read back + * Return: + * I2C_STATUS_OK if read success, else inidcate error + *****************************************************************************/ +static int32_t afe_register_read_word(uint8_t index, uint16_t *dat) +{ + int32_t ret; + uint8_t i; + + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_read_word(index); + if(ret >= num_0) break; + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + + *dat = (uint16_t)ret; + + return ret; +} + + +/***************************************************************************** + * Description: + * wrapper function for operation register word writing + * Parameters: + * index: register index to be read + * dat: write data + * Return: + * see I2C_STATUS_XXX define + *****************************************************************************/ +#if 0 +static int32_t afe_register_write_word(uint8_t index, uint16_t dat) +{ + int32_t ret; + uint8_t i; + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_write_word(index, dat); + if(ret >= num_0) break; + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + + return ret; +} +#endif + + + +/***************************************************************************** + * Description: + * wrapper function to read cell voltage + * Parameters: + * vol: buffer to store voltage read back + * Return: + * see I2C_STATUS_XXX define + * Note: + * it's acceptable if one or more times reading fail + *****************************************************************************/ +int32_t afe_read_cell_volt(int32_t *voltage) +{ + int32_t ret; + uint8_t i; + int32_t buf; + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_cell_voltage_read(&buf); + if(ret >= num_0) + break; + msleep(5); + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + if(oz8806_cell_num > num_1) + { + //*voltage = buf * num_1000 / res_divider_ratio; + bmu_dbg("read from register %d mv \n",buf); + *voltage = buf * res_divider_ratio / num_1000; // res_divider_ratio = ((Rpull + Rdown) / Rdown) * 1000 + *voltage /= oz8806_cell_num; + } + else + *voltage = buf; + return ret; +} + + +/***************************************************************************** + * Description: + * wrapper function to read cell ocv voltage + * Parameters: + * vol: buffer to store voltage read back + + * Return: + * see I2C_STATUS_XXX define + * Note: + * it's acceptable if one or more times reading fail + *****************************************************************************/ +static int32_t afe_read_ocv_volt(int32_t *voltage) +{ + int32_t ret; + uint8_t i; + int32_t buf; + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_ocv_voltage_read(&buf); + if(ret >= num_0) + break; + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + + if(oz8806_cell_num > num_1) + { + *voltage = buf * num_1000 / res_divider_ratio; + *voltage /= oz8806_cell_num; + } + else + *voltage = buf; + + return ret; +} + +/***************************************************************************** + * Description: + * wrapper function to read current + * Parameters: + * dat: buffer to store current value read back + * Return: + * see I2C_STATUS_XXX define + * Note: + * it's acceptable if one or more times reading fail + *****************************************************************************/ +int32_t afe_read_current(int32_t *dat) +{ + int32_t ret; + uint8_t i; + int32_t buf; + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_current_read(&buf); + if(ret >= num_0) + break; + msleep(5); + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + *dat = buf; + return ret; +} + + +/***************************************************************************** + * Description: + * wrapper function to read CAR(accummulated current calculation) + * Parameters: + * dat: buffer to store current value read back + * Return: + * see I2C_STATUS_XXX define + * Note: + * it's acceptable if one or more times reading fail + *****************************************************************************/ +static int32_t afe_read_car(int32_t *dat) +{ + int32_t ret; + uint8_t i; + int32_t buf; + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_car_read(&buf); + if(ret >= num_0) + break; + msleep(5); + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + *dat = buf; + return ret; +} + + + +/***************************************************************************** + * Description: + * wrapper function to write car + * Parameters: + * dat: buffer to store current value read back + * Return: + * see I2C_STATUS_XXX define + * Note: + * it's acceptable if one or more times reading fail + *****************************************************************************/ +static int32_t afe_write_car(int32_t date) +{ + int32_t ret; + uint8_t i; + + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_car_write(date); + if(ret >= num_0) break; + msleep(5); + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + return ret; +} + +/***************************************************************************** + * Description: + * wrapper function to write board offset + * Parameters: + * dat: buffer to store current value read back + * Return: + * see I2C_STATUS_XXX define + * Note: + * it's acceptable if one or more times reading fail + *****************************************************************************/ +static int32_t afe_write_board_offset(int32_t date) +{ + int32_t ret; + uint8_t i; + + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_board_offset_write(date); + if(ret >= num_0) break; + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + return ret; +} + +/***************************************************************************** + * Description: + * wrapper function to read board offset + * Parameters: + * dat: buffer to store current value read back + * Return: + * see I2C_STATUS_XXX define + * Note: + * it's acceptable if one or more times reading fail + *****************************************************************************/ +static int32_t afe_read_board_offset(int32_t *dat) +{ + int32_t ret; + uint8_t i; + int32_t buf; + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_board_offset_read(&buf); + if(ret >= num_0) + break; + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + *dat = buf; + return ret; +} +/***************************************************************************** + * Description: + * wrapper function to read temp + * Parameters: + * dat: buffer to store current value read back + * Return: + * see I2C_STATUS_XXX define + * Note: + * it's acceptable if one or more times reading fail + *****************************************************************************/ +static int32_t afe_read_cell_temp(int32_t *data) +{ + int32_t ret; + uint8_t i; + int32_t temp; + int32_t buf; + + if (gas_gauge->ext_temp_measure) + return num_0; + + for(i = num_0; i < RETRY_CNT; i++){ + ret = oz8806_temp_read(&buf); + if(ret >= num_0) break; + msleep(5); + } + if(i >= RETRY_CNT){ + batt_info->i2c_error_times++; + bmu_dbg("yyyy. %s failed, ret %d\n", __func__, ret); + return ret; + } + + + if((buf >= config_data->temp_ref_voltage)|| (buf <= num_0)){ + *data = num_25; + } + else{ + temp = buf * config_data->temp_pull_up; + temp = temp / (config_data->temp_ref_voltage - buf); + *data = one_latitude_table(parameter->cell_temp_num,parameter->temperature,temp); + } + //pr_err("1111111111111 r is %d\n",temp); + return ret; +} + +/***************************************************************************** + * Description: + * pec_calculate + * Parameters: + * ucCrc: source + * ucData: data + * Return: + * crc data + * Note: + * + *****************************************************************************/ +static uint8_t pec_calculate (uint8_t ucCrc, uint8_t ucData) +{ + uint8_t j; + for (j = num_0x80; j != num_0; j >>= num_1) + { + if((ucCrc & num_0x80) != num_0) + { + ucCrc <<= num_1; + ucCrc ^= num_0x07; + } + else + ucCrc <<= num_1; + if (ucData & j) + ucCrc ^= num_0x07; + } + return ucCrc; +} +#if 0 +/***************************************************************************** + * Description: + * i2c_read_byte + * Parameters: + * Return: + * Note: + * + *****************************************************************************/ +static int32_t i2c_read_byte(uint8_t addr,uint8_t index,uint8_t *data) +{ + int32_t ret = 0; + #if 0 + struct i2c_adapter *adap=parameter->client->adapter; + struct i2c_msg msgs[num_2]; + int scl_rate= num_100 * num_1000; + msgs[num_0].addr = addr; + msgs[num_0].flags = parameter->client->flags; + msgs[num_0].len = num_1; + msgs[num_0].buf = &index; + msgs[num_0].scl_rate = scl_rate; + + msgs[num_1].addr = addr; + msgs[num_1].flags = parameter->client->flags | I2C_M_RD; + msgs[num_1].len = num_1; + msgs[num_1].buf = (char *)data; + msgs[num_1].scl_rate = scl_rate; + + ret = i2c_transfer(adap, msgs, num_2); + + #endif + return (ret == num_2)? num_0 : ret; +} + +/***************************************************************************** + * Description: + * i2c_write_byte + * Parameters: + * Return: + * Note: + * + *****************************************************************************/ +static int32_t i2c_write_byte(uint8_t addr,uint8_t index,uint8_t data) +{ + int32_t ret = 0; + #if 0 + struct i2c_adapter *adap=parameter->client->adapter; + struct i2c_msg msg; + int32_t scl_rate = num_100 * num_1000; + + char tx_buf[num_3]; + tx_buf[num_0] = index; + tx_buf[num_1] = data; + + msg.addr = addr; + msg.flags = parameter->client->flags; + msg.len = num_2; + msg.buf = (char *)tx_buf; + msg.scl_rate = scl_rate; + + if(oz8806_pec_check) + { + msg.len = num_3; + tx_buf[num_2] = num_0; + tx_buf[num_2] =pec_calculate(tx_buf[num_2],(addr<sCaMAH); + batt_info->fRCPrev = batt_info->sCaMAH; + batt_info->fRC = batt_info->sCaMAH; + } +} +EXPORT_SYMBOL(bmu_reinit); + +#ifdef CONFIG_OZ8806_M +static int __init bmulib_init(void) +#else +int bmulib_init(void) +#endif +{ + int ret = 0; +#if !defined(OZ8806_API) + uint32_t byte_num = 0; + uint8_t * p = NULL; +#endif + + pr_err("%s\n", __func__); + + //NOTICE: Don't change the sequence of calling below functions + +#ifdef OZ8806_API + bmu_kernel_memaddr = oz8806_get_kernel_memaddr(); +#else + byte_num = sizeof(config_data_t) + sizeof(bmu_data_t) + sizeof(gas_gauge_t); + p = kzalloc(byte_num, GFP_KERNEL); + bmu_kernel_memaddr = (unsigned long)p; +#endif + if (!bmu_kernel_memaddr) + goto fail_mem; + + parameter_customer.client = oz8806_get_client(); + if (!parameter_customer.client) + goto fail_i2c; + pr_err("i2c address:%x\n", parameter_customer.client->addr); + //struct oz8806_data *data = i2c_get_clientdata(parameter_customer.client); + + bmu_init_parameter(¶meter_customer); + + bmu_init_parameter_more(¶meter_customer); + + bmu_init_chip(¶meter_customer); + + oz8806_set_batt_info_ptr(batt_info); + + oz8806_set_gas_gauge(gas_gauge); + + oz8806_register_bmu_callback(&bmu_polling_loop, &bmu_wake_up_chip, &bmu_power_down_chip, + &charge_end_process, &discharge_end_process, + &oz8806_temp_read, &afe_read_current, &afe_read_cell_volt); + + return ret; +fail_mem: + pr_err("%s: bmu_kernel_memaddr error\n", __func__); + +fail_i2c: + pr_err("%s: oz8806 i2c register error\n", __func__); + return -1; +} + +#ifdef CONFIG_OZ8806_M +static void __exit bmulib_exit(void) +#else +void bmulib_exit(void) +#endif +{ + pr_err("%s\n", __func__); + unregister_bmu_callback(); + +#if !defined(OZ8806_API) + if (bmu_kernel_memaddr) + kfree((int8_t *)bmu_kernel_memaddr); + bmu_kernel_memaddr = 0; +#endif +} + +#ifdef CONFIG_OZ8806_M +//module_init(bmulib_init); +late_initcall(bmulib_init); +module_exit(bmulib_exit); + +MODULE_AUTHOR("O2Micro"); +MODULE_DESCRIPTION("o2micro oz8806 battery gauge driver"); +//MODULE_LICENSE("GPL"); +#endif + diff --git a/drivers/power/sd77426_fg_mmi/bmulib.o b/drivers/power/sd77426_fg_mmi/bmulib.o deleted file mode 100644 index 907a72a03a92..000000000000 Binary files a/drivers/power/sd77426_fg_mmi/bmulib.o and /dev/null differ diff --git a/drivers/power/sd77426_fg_mmi/calculate.o b/drivers/power/sd77426_fg_mmi/calculate.o new file mode 100644 index 000000000000..634c83461468 Binary files /dev/null and b/drivers/power/sd77426_fg_mmi/calculate.o differ diff --git a/drivers/power/sd77426_fg_mmi/oz8806_battery.c b/drivers/power/sd77426_fg_mmi/oz8806_battery.c index 0ab63a9bc164..b9fb02ad97d3 100644 --- a/drivers/power/sd77426_fg_mmi/oz8806_battery.c +++ b/drivers/power/sd77426_fg_mmi/oz8806_battery.c @@ -24,9 +24,8 @@ #include #include #include -//#include #include - +#include //you must add these here for O2MICRO #include "parameter.h" #include "table.h" @@ -42,7 +41,12 @@ static int fg_hw_init_done = 0; static uint8_t bmu_init_done = 0; static int oz8806_suspend = 0; static DEFINE_MUTEX(update_mutex); +#ifdef OZ8806_API +struct mutex *update_mutex_ptr = &update_mutex; +bmu_data_t *batt_info_ptr = NULL; +#else static bmu_data_t *batt_info_ptr = NULL; +#endif static gas_gauge_t *gas_gauge_ptr = NULL; static uint8_t charger_finish = 0; static unsigned long ic_wakeup_time = 0; @@ -333,6 +337,13 @@ static ssize_t oz8806_debug_store(struct device *dev, struct device_attribute *a return _count; } +static ssize_t oz8806_save_capacity_show(struct device *dev, struct device_attribute *attr,char *buf) +{ + if (capacity_init_ok && gas_gauge_ptr && gas_gauge_ptr->stored_capacity) + return sprintf(buf,"%d\n", gas_gauge_ptr->stored_capacity); + + return sprintf(buf,"%d\n", save_capacity); +} static ssize_t oz8806_bmu_init_done_show(struct device *dev, struct device_attribute *attr,char *buf) { @@ -369,51 +380,12 @@ static ssize_t oz8806_bmu_init_done_store(struct device *dev, struct device_attr schedule_delayed_work(&the_oz8806->work, 0); return _count; } -static ssize_t oz8806_save_capacity_show(struct device *dev, struct device_attribute *attr,char *buf) -{ - if (capacity_init_ok && gas_gauge_ptr && gas_gauge_ptr->stored_capacity) - return sprintf(buf,"%d\n", gas_gauge_ptr->stored_capacity); - - return sprintf(buf,"%d\n", save_capacity); -} -#ifdef USERSPACE_READ_SAVED_CAP -static ssize_t oz8806_save_capacity_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - int val; - struct oz8806_data *oz8806; - - if (&(the_oz8806->myclient->dev) == dev) - oz8806 = dev_get_drvdata(dev); - else //this device is the private device of power supply - oz8806 = dev_get_drvdata(dev->parent); - - if (kstrtoint(buf, 10, &val)) - return -EINVAL; - save_capacity = val; - batt_dbg("save_capacity:%d\n", save_capacity); - - if (oz8806 && !bmu_init_done) - { - cancel_delayed_work(&oz8806->work); - schedule_delayed_work(&oz8806->work, 0); - } - - return count; -} -#endif static DEVICE_ATTR(registers, S_IRUGO | (S_IWUSR|S_IWGRP), oz8806_register_show, oz8806_register_store); static DEVICE_ATTR(chip_id, S_IRUGO, oz8806_chip_id_show, NULL); static DEVICE_ATTR(debug, S_IRUGO | (S_IWUSR|S_IWGRP), oz8806_debug_show, oz8806_debug_store); -static DEVICE_ATTR(bmu_init_done, S_IRUGO| (S_IWUSR|S_IWGRP), oz8806_bmu_init_done_show, oz8806_bmu_init_done_store); - -#ifdef USERSPACE_READ_SAVED_CAP -static DEVICE_ATTR(save_capacity, S_IRUGO | (S_IWUSR|S_IWGRP), oz8806_save_capacity_show, oz8806_save_capacity_store); -#else static DEVICE_ATTR(save_capacity, S_IRUGO, oz8806_save_capacity_show, NULL); -#endif - - +static DEVICE_ATTR(bmu_init_done, S_IRUGO| (S_IWUSR|S_IWGRP), oz8806_bmu_init_done_show, oz8806_bmu_init_done_store); static struct attribute *oz8806_attributes[] = { &dev_attr_registers.attr, &dev_attr_chip_id.attr, @@ -513,19 +485,11 @@ static int32_t oz8806_update_bits(struct oz8806_data *data, uint8_t reg, uint8_t else return 0; } -#if 0 -static int oz8806_check_battery_status(struct oz8806_data *data) + +void oz8806_reset_wkuptime(void) { - uint8_t val; - int ret = 0; - - ret = oz8806_read_byte(data, OZ8806_OP_BATTERY_ID, &val); - - pr_err("battery ID: 0x%02x\n", val); - - return ret; + ic_wakeup_time = 0; } -#endif int oz8806_wakeup_full_power(void) { uint8_t val = 0; @@ -586,8 +550,7 @@ static void discharge_end_fun(struct oz8806_data *data) { batt_info_ptr->fRSOC = 0; batt_info_ptr->sCaMAH = data->batt_info.batt_fcc_data / num_100 -1; - if (bmu_discharge_end_process_callback) - bmu_discharge_end_process_callback(); + discharge_end_process(); } else if(batt_info_ptr->fRSOC > 0){ batt_info_ptr->sCaMAH = batt_info_ptr->fRSOC * data->batt_info.batt_fcc_data / num_100 - 1; @@ -650,18 +613,6 @@ static void charge_end_fun(void) #endif return; } - /* - if(adapter_status == CHARGER_USB) - { - gas_gauge_ptr->fast_charge_step = 1; - } - else - { - gas_gauge_ptr->fast_charge_step = 2; - } - */ - - if((batt_info_ptr->fVolt >= (config_data.charge_cv_voltage - 50))&&(batt_info_ptr->fCurr >= DISCH_CURRENT_TH) && (batt_info_ptr->fCurr < oz8806_eoc)&& (!gas_gauge_ptr->charge_end)) @@ -765,9 +716,7 @@ charger_full: { batt_dbg("enter charger charge end"); gas_gauge_ptr->charge_end = 1; - - if (bmu_charge_end_process_callback) - bmu_charge_end_process_callback(); + charge_end_process(); charger_finish = 0; chgr_full_soc_pursue_start = 0; @@ -876,6 +825,7 @@ static void oz8806_lock_soc(struct oz8806_data *data) car = rsoc_pre * data->batt_info.batt_fcc_data / 100; temp = (car * config_data.fRsense) / config_data.dbCARLSB; //transfer to CAR + temp /= 1000; i2c_smbus_write_word_data(data->myclient, OZ8806_OP_CAR,(unsigned short)temp); } @@ -892,12 +842,14 @@ static void oz8806_lock_soc(struct oz8806_data *data) batt_info_ptr->fRC = car; batt_info_ptr->fRCPrev = car; temp = (car * config_data.fRsense) / config_data.dbCARLSB; //transfer to CAR + temp /= 1000; i2c_smbus_write_word_data(data->myclient, OZ8806_OP_CAR,(unsigned short)temp); } } } } + static void oz8806_battery_func(struct oz8806_data *data) { unsigned long time_since_last_update_ms = 0; @@ -924,8 +876,8 @@ static void oz8806_battery_func(struct oz8806_data *data) /**************mutex_lock*********************/ mutex_lock(&update_mutex); - if (bmu_polling_loop_callback && !oz8806_suspend) - bmu_polling_loop_callback(); + if (!oz8806_suspend) + bmu_polling_loop(); oz8806_update_batt_info(data); @@ -974,8 +926,6 @@ int32_t is_battery_exchanged(void) } EXPORT_SYMBOL(is_battery_exchanged); - - static int oz8806_suspend_notifier(struct notifier_block *nb, unsigned long event, void *dummy) @@ -998,8 +948,7 @@ static int oz8806_suspend_notifier(struct notifier_block *nb, mutex_lock(&update_mutex); // if AC charge can't wake up every 1 min,you must remove the if. if(adapter_status == O2_CHARGER_BATTERY) - if (bmu_wake_up_chip_callback) - bmu_wake_up_chip_callback(); + bmu_wake_up_chip(); oz8806_update_batt_info(data); mutex_unlock(&update_mutex); @@ -1047,7 +996,7 @@ static void oz8806_init_soc(struct oz8806_data *data) temp = (int16_t)ret; temp = temp * config_data.dbCARLSB; - temp = temp / config_data.fRsense; + temp = temp * 1000 / config_data.fRsense; if(temp > 5) { init_soc = temp * 100 / config_data.design_capacity - 1; @@ -1174,8 +1123,8 @@ int oz8806_get_battry_current(void) mutex_lock(&update_mutex); - if (oz8806_current_read_callback && batt_info_ptr) - ret = oz8806_current_read_callback(&batt_info_ptr->fCurr); + if (batt_info_ptr) + ret = afe_read_current(&batt_info_ptr->fCurr); if (ret < 0) { @@ -1200,8 +1149,8 @@ int oz8806_get_battery_voltage(void) mutex_lock(&update_mutex); - if (oz8806_voltage_read_callback && batt_info_ptr) - ret = oz8806_voltage_read_callback(&batt_info_ptr->fVolt); + if (batt_info_ptr) + ret = afe_read_cell_volt(&batt_info_ptr->fVolt); if (ret < 0) { @@ -1248,8 +1197,7 @@ int32_t oz8806_vbus_voltage(void) int32_t vbus_voltage = 0; int ret = -1; - if (oz8806_temp_read_callback) - ret = oz8806_temp_read_callback(&vbus_voltage); + ret =oz8806_temp_read(&vbus_voltage); if (ret < 0) { @@ -1267,6 +1215,7 @@ EXPORT_SYMBOL(oz8806_vbus_voltage); int32_t oz8806_get_simulated_temp(void) { return 25; + } EXPORT_SYMBOL(oz8806_get_simulated_temp); @@ -1323,8 +1272,7 @@ void oz8806_register_bmu_callback(void *bmu_polling_loop_func, oz8806_current_read_callback = oz8806_current_read_func; oz8806_voltage_read_callback = oz8806_voltage_read_func; - if(bmu_polling_loop_callback) - bmu_polling_loop_callback(); + bmu_polling_loop(); mutex_unlock(&update_mutex); } @@ -1404,6 +1352,18 @@ int oz8806_get_save_capacity(void) } EXPORT_SYMBOL(oz8806_get_save_capacity); +unsigned long oz8806_get_system_boot_time(void) +{ + unsigned long long time_sec; + unsigned long mod; + time_sec = ktime_to_ns(ktime_get_boottime()); + mod = do_div(time_sec,1000000); + batt_dbg("system boottime: %lu ms", (unsigned long)time_sec); + + return time_sec; +} +EXPORT_SYMBOL(oz8806_get_system_boot_time); + unsigned long oz8806_get_boot_up_time(void) { unsigned long long t; @@ -1419,10 +1379,10 @@ EXPORT_SYMBOL(oz8806_get_boot_up_time); unsigned long oz8806_get_power_on_time(void) { unsigned int t = 0; - pr_info("jiffies %lu,ic_wakeup_time %lu\n",jiffies,ic_wakeup_time); + pr_err("jiffies %lu,ic_wakeup_time %lu\n",jiffies,ic_wakeup_time); t = jiffies_to_msecs(jiffies - ic_wakeup_time); - pr_info("IC wakeup time: %u ms\n", t); + pr_err("IC wakeup time: %u ms\n", t); return (unsigned long)t; } @@ -1492,7 +1452,6 @@ static int oz8806_probe(struct i2c_client *client,const struct i2c_device_id *id pr_err("failed to register power_supply battery\n"); goto register_fail; } - /* * /sys/class/i2c-dev/i2c-2/device/2-002f/ */ @@ -1537,13 +1496,10 @@ static int oz8806_remove(struct i2c_client *client) mutex_lock(&update_mutex); - if (bmu_power_down_chip_callback) - { - //这里需要注意,在关机流程中,必须要调用关机回调,否则芯片可能没有正常休眠,导致下次开机容量异常 - //并且要小心回调之后,如果有work或者线程跑起来,可能会再次唤醒芯片,要避免这种情况。 + //这里需要注意,在关机流程中,必须要调用关机回调,否则芯片可能没有正常休眠,导致下次开机容量异常 + //并且要小心回调之后,如果有work或者线程跑起来,可能会再次唤醒芯片,要避免这种情况。 fg_hw_init_done = 0;//be carefull other thread call bmu_polling_loop_func and wake up chip again - bmu_power_down_chip_callback(); - } + bmu_power_down_chip(); oz8806_update_batt_info(data); @@ -1565,13 +1521,11 @@ static void oz8806_shutdown(struct i2c_client *client) sysfs_remove_group(&(data->myclient->dev.kobj), &oz8806_attribute_group); mutex_lock(&update_mutex); - if (bmu_power_down_chip_callback) - { - //这里需要注意,在关机流程中,必须要调用关机回调,否则芯片可能没有正常休眠,导致下次开机容量异常 - //并且要小心回调之后,如果有work或者线程跑起来,可能会再次唤醒芯片,要避免这种情况。 - fg_hw_init_done = 0; - bmu_power_down_chip_callback(); - } + + //这里需要注意,在关机流程中,必须要调用关机回调,否则芯片可能没有正常休眠,导致下次开机容量异常 + //并且要小心回调之后,如果有work或者线程跑起来,可能会再次唤醒芯片,要避免这种情况。 + fg_hw_init_done = 0; + bmu_power_down_chip(); oz8806_update_batt_info(data); mutex_unlock(&update_mutex); @@ -1597,7 +1551,7 @@ static struct i2c_driver oz8806_driver = { .of_match_table = oz8806_of_match, }, .probe = oz8806_probe, - .remove = oz8806_remove, + .remove = oz8806_remove, .shutdown = oz8806_shutdown, .id_table = oz8806_id, }; diff --git a/drivers/power/sd77426_fg_mmi/parameter.c b/drivers/power/sd77426_fg_mmi/parameter.c index 58c22530a9ea..3b8cc390816a 100644 --- a/drivers/power/sd77426_fg_mmi/parameter.c +++ b/drivers/power/sd77426_fg_mmi/parameter.c @@ -117,6 +117,7 @@ void bmu_init_gg(gas_gauge_t *gas_gauge) gas_gauge->ri = 18; gas_gauge->line_impedance = 10; + gas_gauge->power_on_100_vol = O2_OCV_100_VOLTAGE; #if 0 //add this for oinom diff --git a/drivers/power/sd77426_fg_mmi/parameter.h b/drivers/power/sd77426_fg_mmi/parameter.h index 2aa57fcce29d..e5436f11fb31 100644 --- a/drivers/power/sd77426_fg_mmi/parameter.h +++ b/drivers/power/sd77426_fg_mmi/parameter.h @@ -34,8 +34,14 @@ //#define MUTEX_TIMEOUT 5000 #define MYDRIVER "oz8806" //"oz8806" +//#define OZ8806_API +//#define BAT_STAT + +//two cells application +//#define OZ8806_VME_SEL + #define DISCH_CURRENT_TH -10 -#define O2_OCV_100_VOLTAGE (xaxis_table[X_AXIS - 1]) +#define O2_OCV_100_VOLTAGE 8700 #define TEMPERATURE_DATA_NUM 28 #define num_0 0 @@ -107,6 +113,10 @@ struct oz8806_data struct power_supply *usb_psy; struct delayed_work work; +#ifdef BAT_STAT + struct delayed_work bat_monitor_work; + int32_t bat_changed; +#endif unsigned int interval; struct i2c_client *myclient; @@ -118,7 +128,7 @@ struct oz8806_data typedef struct tag_config_data { - int32_t fRsense; //= 20; //Rsense value of chip, in mini ohm + int32_t fRsense; //= 20 * 1000; //Rsense value of chip, in mini ohm expand 1000 times int32_t temp_pull_up; //230000; int32_t temp_ref_voltage; //1800;1.8v int32_t dbCARLSB; //= 5.0; //LSB of CAR, comes from spec @@ -241,6 +251,7 @@ typedef struct tag_gas_gauge { uint8_t lower_capacity_soc_start; uint8_t percent_10_reserve; + uint32_t power_on_100_vol; }gas_gauge_t; /**************************************************************************** @@ -254,6 +265,8 @@ extern int ZAxisElement[ZAxis]; extern int RCtable[YAxis*ZAxis][XAxis]; //extern one_latitude_data_t charge_data[CHARGE_DATA_NUM]; +extern uint8_t battery_ri ; +extern int32_t one_percent_rc ; /**************************************************************************** * extern variable/function defined by parameter.c @@ -270,6 +283,17 @@ extern int bmulib_init(void); extern void bmulib_exit(void); #endif +//bmulib extern +extern void bmu_polling_loop(void); +extern void bmu_wake_up_chip(void); +extern void bmu_power_down_chip(void); +extern void charge_end_process(void); +extern void discharge_end_process(void); +extern int32_t oz8806_temp_read(int32_t *voltage); +extern int32_t afe_read_current(int32_t *dat); +extern int32_t afe_read_cell_volt(int32_t *voltage); +//endif + #ifdef OZ8806_API //extern void bmu_init_charge_data(uint8_t *dest, uint32_t bytes); extern void bmu_init_XAxisElement(uint8_t *dest, uint32_t bytes); @@ -316,10 +340,11 @@ extern void oz8806_set_batt_info_ptr(bmu_data_t *batt_info); extern void oz8806_set_gas_gauge(gas_gauge_t *gas_gauge); extern int oz8806_get_save_capacity(void); extern int oz8806_get_soc_from_ext(void); +extern unsigned long oz8806_get_system_boot_time(void); extern unsigned long oz8806_get_power_on_time(void); extern unsigned long oz8806_get_boot_up_time(void); extern int oz8806_wakeup_full_power(void); - +extern void oz8806_reset_wkuptime(void); /**************************************************************************** * extern variable/function defined by oz8806_api_dev.c. * This file is deprecated in Linux system. @@ -331,5 +356,37 @@ extern void bmu_call(void); extern int is_battery_exchanged(void); + +#define bmu_dbg(fmt, args...)\ +do {\ + if(parameter->config->debug)\ + printk(KERN_ERR pr_fmt(fmt), ## args);\ +} while(0) +extern int32_t calculate_soc_result(void); +extern int32_t one_latitude_table(int32_t number,one_latitude_data_t *data,int32_t value); +extern uint8_t OZ8806_LookUpRCTable(int infVolt,int infCurr, int infTemp, int *infCal); +void charge_process(void); +void discharge_process(void); + + +extern bmu_data_t *batt_info; +extern gas_gauge_t *gas_gauge; +extern parameter_data_t parameter_customer; +extern parameter_data_t *parameter; + +extern int *rc_table; +extern int *xaxis_table; +extern int *yaxis_table; +extern int *zaxis_table; + + extern int32_t calculate_mah; +extern int32_t calculate_soc ; + +#define X_AXIS gas_gauge->rc_x_num +#define Y_AXIS gas_gauge->rc_y_num +#define Z_AXIS gas_gauge->rc_z_num + + + #endif //end _PARAMETER_H_