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); }
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 = ¶m_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; }