Пример #1
0
/*
 * Initialize the battery cell state structure,
 * Setup initial parameters and timers
 * NOTE: make sure *cell is 0-filled!
 */
void fg_init(struct cell_state *cell, short voltage, short temperature)
{
	unsigned short i;
	struct timespec ts;

	cell->fcc = cell->config->design_capacity;
	cell->qmax = cell->config->design_qmax;
	cell->new_fcc = cell->fcc;

	cell->voltage = voltage;
	cell->prev_voltage = voltage;
	cell->av_voltage = voltage;

	for (i = 0; i < AV_SIZE; i++) {
		av_v[i] = voltage;
		av_c[i] = 0;
	}
	av_v_index = 0;
	av_c_index = 0;

	/*Check for faulty temperature sensor error. Valid operating temerature range -40 to +60 degC */
	if(temperature < -400 || temperature > 600 )
	{
		dev_dbg(cell->dev, "Battery temperature overrange (%d) using room temperature as default. \n", temperature);

		cell->temperature = 250; /* 25C room temperature */
	}
	else
	{
		cell->temperature = temperature;
	}

	/* On init, by-pass temperature debounce check */
	cell->seq_cc_temperature = FG_TEMP_CHANGE_COUNT;

	cell->cycle_count = 1;
#ifdef CONFIG_JET_V2
	cell->temp_index = -1;
	cell->current_bounce_counter=0;
#endif
	cell->learned_cycle = cell->cycle_count;
	cell->prev_soc = -1;

	/*On init, get correct EDV table from temperature compensation*/
	fg_temperature_compensate(cell);

	/* On init, get SOC from OCV */
	fg_ocv(cell);
	printk(KERN_INFO "FG: Init (%dv, %dmAh, %d%%, %dC)\n", voltage, cell->nac, cell->soc, cell->temperature/10);

	/* Update EDV flags */
	fg_update_edv_flags(cell, true);

	getrawmonotonic(&ts);
	cell->last_correction.tv_sec = ts.tv_sec;

	cell->init = true;
}
Пример #2
0
/*
 * Initialize the battery cell state structure,
 * Setup initial parameters and timers
 * NOTE: make sure *cell is 0-filled!
 */
void fg_init(struct cell_state *cell, short voltage)
{
	unsigned short i;

	cell->fcc = cell->config->design_capacity;
	cell->qmax = cell->config->design_qmax;
	cell->new_fcc = cell->fcc;

	cell->voltage = voltage;
	cell->av_voltage = voltage;

	for (i = 0; i < AV_SIZE; i++) {
		av_v[i] = voltage;
		av_c[i] = 0;
	}
	av_v_index = 0;
	av_c_index = 0;

	cell->temperature = 200;
	cell->cycle_count = 1;

	cell->learned_cycle = cell->cycle_count;
	cell->prev_soc = -1;

	/* On init, get SOC from OCV */
	fg_ocv(cell);
	dev_dbg(cell->dev, "FG: Init (%dv, %dmAh, %d%%)\n",
		voltage, cell->nac, cell->soc);

	/* Update EDV flags */
	fg_update_edv_flags(cell);

	do_gettimeofday(&cell->last_correction);

	cell->init = true;
}
Пример #3
0
/* Main FG entry point. This function needs to be called periodically.*/
void fg_process(struct cell_state *cell, short delta_q, short voltage,
		short cur, short temperature)
{
	int i, tmp;
	struct timeval now;

	if (!cell->init)
		return;

	/* Update voltage and add it to the buffer, update average*/
	tmp = 0;
	cell->voltage = voltage;
	av_v_index++;
	av_v_index %= AV_SIZE;
	av_v[av_v_index] = voltage;
	for (i = 0; i < AV_SIZE; i++)
		tmp += av_v[i];
	cell->av_voltage = tmp/AV_SIZE;

	/* Update current and add it to the buffer, update average*/
	tmp = 0;
	cell->cur = cur;
	av_c_index++;
	av_c_index %= AV_SIZE;
	av_c[av_c_index] = cur;
	for (i = 0; i < AV_SIZE; i++)
		tmp += av_c[i];
	cell->av_current = tmp/AV_SIZE;

	/* Update temperature*/
	cell->temperature = temperature;

	/* Check time since last_call */
	do_gettimeofday(&now);
	tmp = now.tv_sec - cell->last_correction.tv_sec;

	/* Check what capacity currection algorithm should we use: OCV or CC */
	if ((tmp > cell->config->ocv->relax_period)
		&& (abs(cell->cur) < cell->config->ocv->long_sleep_current)) {
			fg_ocv(cell);
	} else if (fg_check_relaxed(cell)) {
		/* We are not doing any active CHG/DSG, clear flags
		   this does not compromise learning cycles */
		cell->chg = false;
		cell->dsg = false;

		/* Checking if we can do an OCV correction */
		if (fg_can_ocv(cell))
			fg_ocv(cell);
		else
			fg_cc(cell, delta_q);
	} else /* Not Relaxed: actively charging or discharging */
		fg_cc(cell, delta_q);


	/* Charge / Discharge spesific functionality */
	if (!cell->sleep) {
		if (cell->cur > 0)
			fg_charging(cell, delta_q);
		else if (cell->cur < 0)
			fg_discharging(cell, delta_q);
	}

	/* Update Regular SOC */
	cell->soc = DIV_ROUND_CLOSEST(cell->nac * MAX_PERCENTAGE, cell->fcc);

	fg_update_edv_flags(cell);

	/* Check if battery is full */
	if (cell->nac >= cell->fcc) {
		cell->full = true;
	} else {
		cell->full = false;
		if (cell->nac <= (cell->fcc - cell->config->recharge))
			cell->cc = false;
	}

	/* Checking if we need to set an updated flag (is SOC changed) */
	if (cell->prev_soc != cell->soc) {
		cell->prev_soc = cell->soc;
		cell->updated = true;
	}

	cell->last_correction.tv_sec = now.tv_sec;

#ifdef DEBUG
	/* Printing Debug Data */
	dev_dbg(cell->dev,
		"FG: ACC;%2d ; RM;%4d;mAh ; SOC;%3d;%% ; VOLT;%4d;%4d;mV ; "
		"CUR;%5d;%5d;mA ; "
		"EDV;%dmV/%02d%% ; "
		"LLL;%4d;%4d;%4d ; "
		"N/O;%4d;%4d ; "
		"CS;%4d ; EL;%5d ; "
		"F/C;%d;%d ; CP;%d",
		delta_q, cell->nac, cell->soc, cell->voltage, cell->av_voltage,
		cell->cur, cell->av_current,
		cell->edv.voltage, cell->edv.percent,
		cell->learn_q, cell->learn_offset, cell->ocv_total_q,
		cell->negative_q, cell->overcharge_q,
		cell->cumulative_sleep, cell->electronics_load,
		cell->fcc, cell->cycle_count, tmp);

	print_flags(cell);
#endif
}
Пример #4
0
/* Main FG entry point. This function needs to be called periodically.*/
void fg_process(struct cell_state *cell, short delta_q, short raw_voltage, short norm_voltage,
		short cur, short temperature)
{
	int i, tmp;
	struct timespec now;

	if (!cell->init)
		return;

	/* Update voltage and add it to the buffer, update average*/
	tmp = 0;
	cell->voltage = norm_voltage;
	av_v_index++;
	av_v_index %= AV_SIZE;
	av_v[av_v_index] = norm_voltage;
	for (i = 0; i < AV_SIZE; i++) {
		tmp += av_v[i];
	}
	cell->av_voltage = tmp/AV_SIZE;

	/* Update current and add it to the buffer, update average*/
	tmp = 0;
	cell->cur = cur;
	av_c_index++;
	av_c_index %= AV_SIZE;
	av_c[av_c_index] = cur;
	for (i = 0; i < AV_SIZE; i++)
		tmp += av_c[i];
	cell->av_current = tmp/AV_SIZE;

	/* Update temperature*/
	cell->temperature = temperature;
	/*Update FCC and EDV table from temperature compensation*/
	fg_temperature_compensate(cell);
	/* Check time since last_call */
	getrawmonotonic(&now);
	tmp = now.tv_sec - cell->last_correction.tv_sec;

	/* Check what capacity correction algorithm should we use: OCV or CC */
	if ((tmp > cell->config->ocv->relax_period) &&
	    (abs(cell->cur) < cell->config->ocv->long_sleep_current)) {
#ifdef CONFIG_POWER_SUPPLY_DEBUG
			printk(KERN_DEBUG "OCV check 1\n");
#endif
			fg_ocv(cell);
	} else if (fg_check_relaxed(cell)) {
		/* We are not doing any active CHG/DSG, clear flags
		   this does not compromise learning cycles */
		cell->chg = false;
		cell->dsg = false;

		/* Checking if we can do an OCV correction */
		if (fg_can_ocv(cell))
			fg_ocv(cell);
		else
			fg_cc(cell, delta_q);
	} else /* Not Relaxed: actively charging or discharging */
		fg_cc(cell, delta_q);


	/* Charge / Discharge spesific functionality */
	if (!cell->sleep) {
		if (cell->cur > 0)
			fg_charging(cell, delta_q);
		else if (cell->cur < 0)
			fg_discharging(cell, delta_q);
	}

	/* Update Regular SOC */
	cell->soc = DIV_ROUND_CLOSEST(cell->nac * MAX_PERCENTAGE, cell->fcc);

/* The voltage will vibrate a lot when close to shutdown voltage. This happens especially when running high power
 * consumption app. So need to take care of the end check
*/

	/*Add here to check both nac and EDV0*/
	if(cell->soc > EDV_FIRST_CHECK_POINT+5){
		fg_ocv_check(cell);
	}
	else if(cell->soc==0){
#ifdef BATTERY_DRAIN_CONFIG
		cell->soc=1;
#else
		fg_check_end(cell);
#endif
	}

	/* When SOC is below 15%, check if raw voltage level reached hardware shutdown threshold */
	if(cell->soc < EDV_FIRST_CHECK_POINT+5){
		fg_check_shutdown_voltage(cell, raw_voltage);
	}

	fg_update_edv_flags(cell, false);

	/* Check if battery is full */
	if (cell->cc) {
		cell->full = true;
	}

	if (cell->soc < MAX_PERCENTAGE) {
		cell->full = false;
		if (cell->nac <= (cell->fcc - cell->config->recharge))
			cell->cc = false;
	}

	/* Check if SOC reached 100% and battery is still charging, then keep SOC at 99% */
	if((*cell->charge_status == POWER_SUPPLY_STATUS_CHARGING) &&
			(cell->soc == MAX_PERCENTAGE) && !cell->cc && !cell->full)
	{
#ifdef DEBUG
		printk(KERN_DEBUG "End of charge not reach yet\n");
#endif
		cell->soc = MAX_PERCENTAGE-1;
	}

	/* Checking if we need to set an updated flag (is SOC changed) */
	if (cell->prev_soc != cell->soc) {
		cell->prev_soc = cell->soc;
		cell->updated = true;
	}

	cell->last_correction.tv_sec = now.tv_sec;

#if 0
	//JET-376 test, run calibration every 5-min to check cc_offset value
	cal_cntr++;
	if(cal_cntr >= 30)
	{
		cell->calibrate = true;
		cal_cntr = 0;
		printk(KERN_DEBUG "PMIC Calibrate now! \n");
	}
#endif

#ifdef DEBUG
	/* Printing Debug Data */
	printk(KERN_DEBUG
		"FG:ACC:%2d; RM:%4d,mAh; SOC:%3d%%; VOLT:%4d,%4d,mV; "
		"CUR:%5d,%5d,mA; TEMP:%3d; "
		"EDV:%d,mV,%02d%%; "
		"LLL:%4d,%4d,%4d; "
		"N/O:%4d,%4d; "
		"CS:%4d; EL:%5d; "
		"FCC:%d,%d; CP:%d; \n",
		delta_q, cell->nac, cell->soc, cell->voltage, cell->av_voltage,
		cell->cur, cell->av_current, cell->temperature,
		cell->edv.voltage, cell->edv.percent,
		cell->learn_q, cell->learn_offset, cell->ocv_total_q,
		cell->negative_q, cell->overcharge_q,
		cell->cumulative_sleep, cell->electronics_load,
		cell->fcc, cell->cycle_count, tmp);

	print_flags(cell);
#endif
}
Пример #5
0
static void fg_temperature_compensate(struct cell_state *cell)
{
	int i;
#ifdef SOC_CHANGE_ON_TEMPERATURE
	short fcc_start,uc;
	short soc_new,soc_start,soc_new_start;
#else
	short soc;
#endif
	int table_size = ARRAY_SIZE(temp_config_table);
	short temp=cell->temperature;

	/* Check for faulty temperature sensor error. Valid operating temerature range -40 to +60 degC */
	if(temp < -400 || temp > 600 )
	{
		dev_dbg(cell->dev, "Battery temperature overrange (%d) using room temperature as default. \n", temp);

		i=0;	//ENV25 room temp curve
	}
	else
	{
		//Round to closest integer
		if(temp>=0)
			temp=(temp+5)/10;
		else
			temp=(temp-5)/10;
		for(i=0; i<table_size; i++)
		{
			if(temp>temp_config_table[i].temp_th)
				break;
		}
		/*if exceed the lowest threshold*/
		if(i>=table_size)
			i=table_size-1;
	}

	if(cell->temp_index!=i){//temperature range changed

		/* temperature debounce check */
		cell->seq_cc_temperature++;
		dev_dbg(cell->dev, "Temperature range change detected #%d [%d:%d  %dC]\n",
				cell->seq_cc_temperature,cell->temp_index,i,temp);
	}
	else {
		cell->seq_cc_temperature = 0;
	}

	if (cell->seq_cc_temperature > FG_TEMP_CHANGE_COUNT) {
		cell->seq_cc_temperature = 0;

#ifdef SOC_CHANGE_ON_TEMPERATURE
		/*scaling fcc and nac due to temperature change*/
		fcc_start=cell->fcc;
		cell->fcc=temp_config_table[i].temp_max_capacity;

		uc= cell->nac_start - cell->nac;
		/*Calculate new SOC*/
		soc_start=DIV_ROUND_CLOSEST(cell->nac_start * MAX_PERCENTAGE, fcc_start);

		soc_new_start=DIV_ROUND_CLOSEST(soc_start * cell->fcc, fcc_start);
		soc_new=soc_new_start - 
				DIV_ROUND_CLOSEST(uc * MAX_PERCENTAGE, cell->fcc);

		if((cell->soc > EDV_FIRST_CHECK_POINT)&&(soc_new > 0) )
			cell->soc= soc_new;
		/*Else let EDV check to determine the real change here*/

		cell->nac=DIV_ROUND_CLOSEST(cell->fcc * cell->soc, MAX_PERCENTAGE);
		dev_dbg(cell->dev, "Temperature Correction %d:NS%d:SOCn%d\n", temp, cell->nac_start, soc_new);
		/*Update nac_start*/
		cell->nac_start=cell->nac;
#else
		/*SOC didn't change from temperature variation*/
		//TODO - reverting back to original code, it prevents the SOC increase when temperature increase.
		//TODO - needs to revisit when doing temperature changes.
		if(cell->temp_index>i)//Battery temperature increase
		{
			if(fg_current_debounce_check(cell)==false)
				return;
			if(cell->cur < 0){
				soc=voltage_cap_table(i, cell->av_voltage);
				cell->prev_voltage=cell->av_voltage;
				dev_dbg(cell->dev, "Temperature Increase soc=%d\n",soc);
				if(soc> cell->soc){
#ifdef CONFIG_JET_SUN//Assume sun has more accurate fuel gauge
					cell->soc=soc;
#else
					cell->soc=(soc+cell->soc)/2;
#endif
				}
			}
		}
		cell->fcc=temp_config_table[i].temp_max_capacity;
		cell->new_fcc = cell->fcc; //FA found BUG: otherwise overrdes FCC=470 (default) in fg_charging()
		cell->nac=DIV_ROUND_CLOSEST(cell->fcc * cell->soc, MAX_PERCENTAGE);
		dev_dbg(cell->dev, "Temperature Correction %dC:FCC:%d,NAC:%d,SOC:%d%%\n", temp,cell->fcc,cell->nac,cell->soc);
#endif
		cell->config->edv->edv[0].voltage=temp_config_table[i].edv_voltage[0];
		cell->config->edv->edv[1].voltage=temp_config_table[i].edv_voltage[1];
		cell->config->edv->edv[2].voltage=temp_config_table[i].edv_voltage[2];
		fg_update_edv_flags(cell, true);
		cell->temp_index=i;
	}
}