/**********************************************************
*  Function:       charge_core_sbatt_by_vbat_ichg_handler
*  Discription:    update the charge parameters in different segment charging
*  Parameters:   vbat:battery voltage
*                      segment_data[]:the table for describe the segment property
*                      data:charge parameters
*  return value:  NULL
**********************************************************/
static void charge_core_sbatt_by_vbat_ichg_handler(int vbat, struct charge_segment_data segment_data[], struct charge_core_data *data)
{
    int i,ichg;
    static int last_i = 0;
    static int last_vterm = 0;
    static int last_ichg = 0;
    static int last_vbat = 0;
    static int flag_running_first = 1;

    ichg =  -hisi_battery_current();

    /* choose index of segment_data */
    for (i = 0; i < data->segment_level; i++)
    {
        if ((vbat >= segment_data[i].vbat_min) && (vbat < segment_data[i].vbat_max) && ichg < segment_data[i].ichg_segment)
        {
            if ((last_i - i <= 0) || (segment_data[i].vbat_max - vbat > segment_data[i].volt_back)
               || (abs(last_i - i) > 1) || (flag_running_first == 1))
            {
                /*do nothing,just get index "i" */
            }
            else
            {
                i = i+1;
            }
            break;
        }
    }

    /* if cannot choose right index ,keep last index  */
    if(i == data->segment_level)
    {
        i=last_i;
    }

    /* set ichg and vterm according to index  only when two consecutive index is the same ,or keep last ichg and vterm */
    if(last_i == i || flag_running_first == 1)
    {
        data->ichg = data->ichg < segment_data[i].ichg_segment ? data->ichg : segment_data[i].ichg_segment;
        data->vterm = data->vterm < segment_data[i].vterm_segment ? data->vterm : segment_data[i].vterm_segment;
    }
    else
    {
        data->ichg = data->ichg < last_ichg ? data->ichg :last_ichg;
        data->vterm = data->vterm < last_vterm ? data->vterm : last_vterm;
    }
    hwlog_info("%s :ichg = %d,vbat =%d , last_i =%d, i =%d,segment_data[i].ichg_segment =%d ,data->ichg =%d ,last_ichg = %d \n",
        __func__,ichg,vbat,last_i,i,segment_data[i].ichg_segment,data->ichg,last_ichg);

    last_i = i;
    flag_running_first = 0;
    last_vbat = vbat;
    last_ichg = data->ichg;
    last_vterm = data->vterm;

}
static void get_current_work_func(struct work_struct *work)
{
	int value = 0;

#if 0
	value = hisi_battery_current();
#endif
	/*send current to iom3*/
	if (send_func) {
		(*send_func)(value);
	}

	if(atomic_read(&enabled))
		schedule_delayed_work(&read_current_work, msecs_to_jiffies(READ_CURRENT_INTERVAL));
}
static int calc_capacity_from_voltage(void)
{
    int data  = 50;
    int battery_voltage = 0;
    int battery_current = 0;

    battery_current = -hisi_battery_current();
    battery_voltage = hisi_battery_voltage();//bq27510_battery_voltage(&dev27510);
    if (battery_voltage <= BAT_VOL_3200){
        data = 0;
        return data;
    }
    battery_voltage = hisi_battery_voltage()-120*battery_current/1000;
    if (battery_voltage < BAT_VOL_3500)
        data = 2;
    else if (battery_voltage < BAT_VOL_3550)
        data = 10;
    else if (battery_voltage < BAT_VOL_3600)
        data = 20;
    else if (battery_voltage < BAT_VOL_3700)
        data = 30;
    else if (battery_voltage < BAT_VOL_3800)
        data = 40;    
    else if (battery_voltage < BAT_VOL_3850)
        data = 50;    
    else if (battery_voltage < BAT_VOL_3900)
        data = 60;
    else if (battery_voltage < BAT_VOL_3950)
        data = 65;
    else if (battery_voltage < BAT_VOL_4000)
        data = 70;
    else if (battery_voltage < BAT_VOL_4250)
        data = 85;
    else if (battery_voltage >= BAT_VOL_4250)
       data = 100;
    return data;
}
static int bq_bci_battery_get_property(struct power_supply *psy,
                    enum power_supply_property psp,
                    union power_supply_propval *val)
{
    struct bq_bci_device_info *di;

    di = to_bq_bci_device_info(psy);

    switch (psp) {
    case POWER_SUPPLY_PROP_STATUS:
        val->intval = di->charge_status;
        break;
    case POWER_SUPPLY_PROP_VOLTAGE_NOW:
        di->bat_voltage = hisi_battery_voltage();
        if (COUL_HISI_HI6421V300 == hisi_coulometer_type()){
            val->intval = hisi_battery_voltage_uv();
        }
        else{
            val->intval = di->bat_voltage * 1000;
        }
        break;
    case POWER_SUPPLY_PROP_CURRENT_NOW:
        di->bat_current = hisi_battery_current();
        if(COUL_HISI_HI6421V300 == hisi_coulometer_type()){
            di->bat_current = -(di->bat_current);
        }
        val->intval = di->bat_current;
        break;
    case POWER_SUPPLY_PROP_TEMP:
        val->intval = di->bat_temperature * 10;
        break;
    case POWER_SUPPLY_PROP_PRESENT:
    case POWER_SUPPLY_PROP_ONLINE:
        val->intval = di->bat_exist;
        break;
    case POWER_SUPPLY_PROP_HEALTH:
        val->intval = di->bat_health;
        break;
    case POWER_SUPPLY_PROP_CAPACITY:
        if (modem_off) {
            val->intval = 0;
        }else{
            val->intval = di->capacity;
        }
        break;
    case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
        val->intval = di->bat_capacity_level;
        break;
    case POWER_SUPPLY_PROP_TECHNOLOGY:
        val->intval = di->bat_technolog;
        break;
    case POWER_SUPPLY_PROP_CAPACITY_RM:
        val->intval = di->bat_rm;
        break;
    case POWER_SUPPLY_PROP_CAPACITY_FCC:
        val->intval = di->bat_fcc;
        break;
    case POWER_SUPPLY_PROP_VOLTAGE_MAX:
         val->intval = di->bat_max_volt;
        break;
    case POWER_SUPPLY_PROP_ID_VOLTAGE:
        val->intval = hisi_battery_id_voltage();
        break;
    case POWER_SUPPLY_PROP_BRAND:
        val->strval = hisi_battery_brand();
        break;
    default:
        return -EINVAL;
    }
    return 0;
}
int bq_get_error_info(struct bq_bci_device_info *di)
{
    static int pre_bat_err =0, archive_state = 1;
    static unsigned long timeout_jiffies = 0;
    static int first_in = 1;
    static int pre_uf_capacity = 0;
    static int pre_capacity = 0;
    static int capacity_stay_count = 0;
    static int online_delay_count = 0;
    int bat_uf_capacity = 0;
    int curr_by_coultype = 1;
	int dsm_bci_battery_err_offset = 0;

    if (COUL_HISI_HI6421V300 == hisi_coulometer_type())
        curr_by_coultype = -1;

    di->bat_err = 0;

    if(!is_hisi_battery_exist())
        di->bat_err |= ERROR_BATT_NOT_EXIST;

    if(hisi_battery_temperature()< BQ2419x_COLD_BATTERY_THRESHOLD
           || hisi_battery_temperature()>= BQ2419x_HOT_BATTERY_THRESHOLD)
    {
        if(di->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING)
            di->bat_err |= ERROR_BATT_TEMP_STOP;
        if(di->charge_status == POWER_SUPPLY_STATUS_CHARGING)
            di->bat_err |= ERROR_BATT_TEMP_CHARGE;

        di->bat_err |= ERROR_BATT_TEMP_OUT;
        dev_info(di->dev,"batt temp = %d\n ", hisi_battery_temperature());
    }

    if(di->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING
        && !(bq2419x_get_factory_flag())) {
        if(di->power_supply_status == POWER_SUPPLY_HEALTH_OVERVOLTAGE)
            di->bat_err |= ERROR_VBUS_OVERVOLTAGE;
        if(hisi_battery_voltage() > BATT_OVERVOLTAGE_THRES)
            di->bat_err |= ERROR_BATT_OVERVOLTAGE;

        di->bat_err |= ERROR_BATT_NOT_CHARGING;
    } else {
        if(hisi_battery_voltage() > BATT_OVERVOLTAGE_THRES
           || hisi_battery_voltage() < BATT_LOWVOLTAGE_THRES) {
            di->bat_err |= ERROR_BATT_VOLTAGE;
            dev_info(di->dev,"batt volt = %d\n ", hisi_battery_voltage());
        }
    }

    if(di->chargedone_stat && hisi_battery_capacity() <= CHG_CANT_FULL_THRESHOLD){
        di->bat_err |= ERROR_PRE_CHARGEDONE;
        dev_info(di->dev,"batt capacity = %d\n ", hisi_battery_capacity());
    }

    if(di->charge_status == POWER_SUPPLY_STATUS_CHARGING
       && hisi_battery_current_avg() <= 50
       && hisi_battery_current_avg() >= 10
       && (curr_by_coultype*hisi_battery_current()) <= 50
       && (curr_by_coultype*hisi_battery_current()) >= 10
       && di->capacity == 100) {
        di->bat_err |= ERROR_NO_CHARGEDONE;
        dev_info(di->dev,"batt curr = %d batt curr_avg = %d\n ",
                         (curr_by_coultype*hisi_battery_current()), hisi_battery_current_avg());
    }

    if((!di->usb_online) && (!di->ac_online)){
        if((-hisi_battery_current() > 0) && (online_delay_count++ == 1)){
             di->bat_err |= ERROR_BAD_CURR_SENSOR;
             online_delay_count = 0;
             dev_info(di->dev,"batt curr = %d\n ", (-hisi_battery_current()));
        }
    } else {
        online_delay_count = 0;
    }

    bat_uf_capacity = hisi_battery_unfiltered_capacity();
    if(first_in){
        pre_uf_capacity = bat_uf_capacity;
        pre_capacity = di->capacity;
        first_in = 0;
    } else {
        if (abs(pre_uf_capacity - bat_uf_capacity) >= 3) {
            if (100 != bat_uf_capacity) {
                di->bat_err |= ERROR_UFCAPCITY_DEBOUNCE_OTHER;
            }
            else {
                if (abs(pre_uf_capacity - bat_uf_capacity) > 10)
                    di->bat_err |= ERROR_UFCAPCITY_DEBOUNCE_100;
            }
            hisi_hi6421v300_print_cc_reg(2); //debug
        }
        pre_uf_capacity = bat_uf_capacity;
    }

    if(di->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING
       || di->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
        if(pre_capacity > 0 && di->capacity != pre_capacity) {
            if(di->capacity > REACH_FULL_RESAMPLE_THRESHOLD) {
                if(capacity_stay_count <= 2) {
                    di->bat_err |= ERROR_CAPACITY_CHANGE_FAST;
                    capacity_stay_count = 0;
                }
            } else if (di->capacity < REACH_EMPTY_RESAMPLE_THRESHOLD) {
                if(capacity_stay_count <= 12) {
                    di->bat_err |= ERROR_CAPACITY_CHANGE_FAST;
                    capacity_stay_count = 0;
                }
            } else {
                if(capacity_stay_count <= 6) {
                    di->bat_err |= ERROR_CAPACITY_CHANGE_FAST;
                    capacity_stay_count = 0;
                }
            }
            capacity_stay_count = 0;
        } else {
            capacity_stay_count++;
        }
    }
    pre_capacity = di->capacity;

    if (is_hisi_hi6421v300_fcc_debounce()) {
        di->bat_err |= ERROR_FCC_DEBOUNCE;
    }

    if(di->bat_err != pre_bat_err && archive_state == 1){
        timeout_jiffies = jiffies + msecs_to_jiffies(LOG_ARCH_DELAY_TIME);
        archive_state = 0;
        dev_info(di->dev,"(%s) BATT ERR = %x\n", hisi_battery_brand(), di->bat_err);
    }
    pre_bat_err = di->bat_err;

    if(time_is_before_jiffies(timeout_jiffies) &&  di->bat_err != 0x0 && archive_state == 0){
        //bq_log_exception_archive(di->bat_err);
		if (dsm_client_ocuppy(battery_dclient)) {
			dsm_client_record(battery_dclient, "battery error = %x.\n", di->bat_err);
			dsm_bci_battery_err_offset = get_bit(di->bat_err);
			dsm_client_notify(battery_dclient, DSM_BATTERY_ERROR_NO + dsm_bci_battery_err_offset);
		}
		archive_state = 1;
    }

    return di->bat_err;
}