static int get_battery_temperature(int resistance)
{
	struct power_supply *ps = power_supply_get_by_name(SEMC_BDATA_NAME);
	struct data_info *di = container_of(ps, struct data_info, bdata_ps);
	int i;
	int temp;
	enum battery_technology type;
	int num_table_elements;
	const struct resistance_vs_temperature_semc *table_p;

	type = get_battery_type(resistance);

	if (type == BATTERY_TECHNOLOGY_TYPE1) {
		table_p = &fallback_resistance_vs_temperature_type1[0];
		num_table_elements =
			sizeof(fallback_resistance_vs_temperature_type1) /
			sizeof(struct resistance_vs_temperature_semc);
	} else if (type == BATTERY_TECHNOLOGY_TYPE2) {
		table_p = &fallback_resistance_vs_temperature_type2[0];
		num_table_elements =
			sizeof(fallback_resistance_vs_temperature_type2) /
			sizeof(struct resistance_vs_temperature_semc);
	} else {
		temp = DEFAULT_TEMPERATURE_UNKNOWN_BATT_TYPE;
		return temp;
	}

	for (i = 0; i < num_table_elements; i++) {
		if (resistance < table_p[i].resistance)
			break;
	}

	if ((i > 0) && (i < num_table_elements)) {
		temp = INTERPOLATE(resistance,
					table_p[i].resistance,
					table_p[i].temperature,
					table_p[i-1].resistance,
					table_p[i-1].temperature);
	} else if (i == 0) {
		temp = table_p[0].temperature;
	} else {
		temp = table_p[num_table_elements - 1].temperature;
	}
	dev_dbg(di->dev, "%s() resist=%d type=%d temp=%d\n",
		__func__, resistance, type, temp);
	return temp;
}
static void semc_battery_timer_worker(struct work_struct *work)
{
	enum battery_technology tech;
	int tech_old = 0;
	int temp_old = 0;
	int amb_old = 0;
	u8 got = 0;
	struct data_info *di =
		container_of(work, struct data_info, timer_work);

	if (atomic_cmpxchg(&di->suspend_lock, 0, 1))
		return;

	if (get_batt_therm_resistance(di, &resistance) >= 0) {
		tech = get_battery_type(resistance);
		MUTEX_LOCK(&di->lock);
		tech_old = di->technology;
		temp_old = di->temp_celsius;
		di->technology = get_technology(tech);
		di->temp_celsius = get_battery_temperature(resistance);
		MUTEX_UNLOCK(&di->lock);
		got |= 0x01;
	}
	if (get_battery_temperature_ambient(&ambient_temp) >= 0) {
		MUTEX_LOCK(&di->lock);
		amb_old = di->temp_celsius_amb;
		di->temp_celsius_amb = ambient_temp;
		MUTEX_UNLOCK(&di->lock);
		got |= 0x02;
	}
	atomic_set(&di->suspend_lock, 0);

	if (((got & 0x01) &&
	(di->technology != tech_old || di->temp_celsius != temp_old)) ||
	((got & 0x02) && di->temp_celsius_amb != amb_old))
		power_supply_changed(&di->bdata_ps);

	if (got & 0x03)
		atomic_set(&di->got_bdata, 1);

	dev_dbg(di->dev, "%s() got=%d tech=%d batt_temp=%d ambient_temp=%d\n",
		__func__,
		got, di->technology, di->temp_celsius, di->temp_celsius_amb);

	semc_battery_timer_start(di);
}
Esempio n. 3
0
int max17042_init(int load)
{
	uint16_t data;
	int i;
	static const uint16_t* bufp = (uint16_t*) 0x81000000;

	uint16_t* savestorep;
	int err, retries=2, force_por=0;
	uint16_t designcap;

	type_params = &param_table[get_battery_type(load)];

	designcap = type_params->init_params->Capacity;

	i2c_init(100, MAX17042_ADDR);

	if ( MAX_READ(MAX17042_STATUS, (uchar*)&data) != 0)
	{
	    DEBUG("MAX17042+UBOOT: No battery or 0V battery!\n");
	    return 1;
	}

	DEBUG("MAX17042+UBOOT: gas gauge detected (0x%04x)\n",data);

	//check if we need restore registers inside
	is_power_on_rst();
	if ( is_power_on ) {
		DEBUG("MAX17042+UBOOT:POR detected!\n");
	} else {
		DEBUG("MAX17042+UBOOT:WARM BOOT    \n");
	}

	if (load) {
		run_command("mmcinit 1; fatload mmc 1:5 0x81000000 max17042.bin 0x1000", 0);
	}

	if (*bufp != 0x1234 || !load) {
		DEBUG(" No valid max17042 init data found, assume no battery history \n");
		is_history_exist = 0;
	} else {
		DEBUG(" Valid max17042 init data is loaded into memory \n");
	}		
	
	if ( is_history_exist == 1 ) {

		savestorep = (uint16_t*)&save_store;

		for ( i = 0; i <(sizeof(save_store) / sizeof(uint16_t)); i++) {
			DEBUG (" 0x%04x\n", *bufp);
		
			*savestorep++ = *bufp++;
		}

#define MIN_CAP_AGING 25/100   // allow no less than 25% of design capacity before rejecting
#define MAX_CAP_AGING 13/10   // reject history capacity if it seems overly big
#define MIN_CAPNOM_AGING 25/100   // allow no less than 25% of nominal design capacity before rejecting
#define MAX_CAPNOM_AGING 15/10   // reject history capacity if it seems overly big

	    if ( (save_store.val_FullCAP < (uint16_t)(((uint32_t)designcap)*MIN_CAP_AGING)) ||
		 (save_store.val_FullCAP > (uint16_t)(((uint32_t)designcap)*MAX_CAP_AGING)) ||
	         (save_store.val_FullCAPNom < (uint16_t)(((uint32_t)designcap)*MIN_CAPNOM_AGING)) ||
		 (save_store.val_FullCAPNom > (uint16_t)(((uint32_t)designcap)*MAX_CAPNOM_AGING)) )
		{
 			printf("Resetting battery defaults due to faulty CAPACITY (0x%x, 0x%x)\n",
 				save_store.val_FullCAP, save_store.val_FullCAPNom);

 			force_por = 1;
 			is_history_exist = 0;
		}
	    else
		{
		DEBUG(" verify if mem loaded: FullcapNom was saved as %04x\n", 
			    save_store.val_FullCAPNom );
		}
		
		// In case val_DesignCap in history data does not match battery's design capacity,
		// we should throw away the history data.
		if(save_store.val_DesignCap != designcap) {
			printf("Resetting battery defaults because Design Capactiy(0x%04X)in history data"
			" does not match battery's Design Capacity(0x%04X)\n", 
				save_store.val_DesignCap, designcap);
			force_por = 1;
			is_history_exist = 0;
		} 			
	}

	save_store.val_DesignCap = designcap; 	

	i2c_init(100, 0x36);	//no need

	if ( !is_power_on )
	{
	    // when there is no history file, assume it is a POR
 	    //if ( is_history_exist && max17042_check_init_config() == 0 )
 	    // UPDATE: if history file doesn't exist don't do a POR,
 		if (!force_por && max17042_check_init_config() == 0 )
	    	{
		DEBUG("MAX17042+UBOOT: warm config is okay\n");
		return 0;
	    }
	    else
	    {
		/* when the config is bad but it's not a POR, then something
		 * is quite wrong.
		 */
		DEBUG("MAX17042+UBOOT: warm config bad. soft POR\n");
		is_power_on = 1;

		max17042_soft_por();
	    }
	}

	//1. Delay 500ms
	udelay( 500 * 1000 );
	
	MAX17042_DUMPREG( MAX17042_Version );
	MAX17042_DUMPREG( MAX17042_DesignCap );
	MAX17042_DUMPREG( MAX17042_OCV );
	MAX17042_DUMPREG( MAX17042_FSTAT );
	MAX17042_DUMPREG( MAX17042_SOCvf );

	//2. Init Configuration
	max17042_init_config();

	//3. Save starting para
	max17042_save_start_para();
	
	//4. unlock model access
	max17042_unlock_model();

	do {
		//5. write custom model
		max17042_write_model();
	
		//6. read model
		//7. verify model
		err = max17042_read_verify_model();
	} while ( err != 0 && --retries > 0 );
	if ( retries == 0 ) {
		DEBUG( " writing model failed\n");
		return err;
	}
		
	retries = 2;
	do {		
		//8. lock model access
		max17042_lock_model();
	
		//9. verify model access is locked
		err = max17042_verify_lock_model();
	} while ( err != 0 && --retries > 0 );
	if ( retries == 0 ) {
		DEBUG( " locking model failed\n");
		return err;
	}
	
	//10. write custom parameters
	err = max17042_write_custom_para( );	
	if ( err != 0 ) {
	    DEBUG("write custom parameters failed\n");
	    return err;
	}
	
	//11 update full capacity parameters
	err = max17042_update_cap_para( );
	if ( err != 0 ) {
	    DEBUG("update capacity parameters failed\n");
	    return err;
	}

	//13. delay 350ms;
	udelay ( 350 *1000 );
	
	//14. write VFSOC to VFSCO0
	err = max17042_write_vfsoc();
	if ( err != 0 ) {
	    DEBUG("write vfsoc failed\n");
	    return err;
	}

	/* 15.5 Advance to Colomb-Counter Mode
	 * We do this all the time.  In the factory the battery is fresh (close to
	 * design capacity, and when there is a history file we restore a known good
	 * capacity after this, so that case it's safe to assume we have a good estimate
	 * as well.
	 */
	err = max17042_set_cycles( 0x00A0 );
	if ( err != 0 ) {
	    DEBUG("set cycles 0x00A0 failed\n");
	    return err;
	}

	err = max17042_load_cap_para( );
	if ( err != 0 ) {
	    DEBUG("load capacity parameters failed\n");
	    return err;
	}

	max17042_clear_POR();

	if ( is_history_exist ) {
	    err = max17042_restore_learned_para();
	    if ( err != 0 ) {
		DEBUG("restore learned parameters failed\n");
		return err;
	    }
	}

	is_power_on = 0;

	DEBUG("Max17042 init is done\n");
	
	return 0;
}