static int bq27x00_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { int ret = 0; struct bq27x00_device_info *di = power_supply_get_drvdata(psy); mutex_lock(&di->lock); if (time_is_before_jiffies(di->last_update + 5 * HZ)) { cancel_delayed_work_sync(&di->work); bq27x00_battery_poll(&di->work.work); } mutex_unlock(&di->lock); if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) return -ENODEV; switch (psp) { case POWER_SUPPLY_PROP_STATUS: ret = bq27x00_battery_status(di, val); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: ret = bq27x00_battery_voltage(di, val); break; case POWER_SUPPLY_PROP_PRESENT: val->intval = di->cache.flags < 0 ? 0 : 1; break; case POWER_SUPPLY_PROP_CURRENT_NOW: ret = bq27x00_battery_current(di, val); break; case POWER_SUPPLY_PROP_CAPACITY: ret = bq27x00_simple_value(di->cache.capacity, val); break; case POWER_SUPPLY_PROP_CAPACITY_LEVEL: ret = bq27x00_battery_capacity_level(di, val); break; case POWER_SUPPLY_PROP_TEMP: ret = bq27x00_simple_value(di->cache.temperature, val); if (ret == 0) val->intval -= 2731; break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: ret = bq27x00_simple_value(di->cache.time_to_empty, val); break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: ret = bq27x00_simple_value(di->cache.time_to_empty_avg, val); break; case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: ret = bq27x00_simple_value(di->cache.time_to_full, val); break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; break; case POWER_SUPPLY_PROP_CHARGE_NOW: ret = bq27x00_simple_value(bq27x00_battery_read_nac(di), val); break; case POWER_SUPPLY_PROP_CHARGE_FULL: ret = bq27x00_simple_value(di->cache.charge_full, val); break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: ret = bq27x00_simple_value(di->charge_design_full, val); break; case POWER_SUPPLY_PROP_CYCLE_COUNT: ret = bq27x00_simple_value(di->cache.cycle_count, val); break; case POWER_SUPPLY_PROP_ENERGY_NOW: ret = bq27x00_simple_value(di->cache.energy, val); break; case POWER_SUPPLY_PROP_POWER_AVG: ret = bq27x00_simple_value(di->cache.power_avg, val); break; case POWER_SUPPLY_PROP_HEALTH: ret = bq27x00_simple_value(di->cache.health, val); break; case POWER_SUPPLY_PROP_MANUFACTURER: val->strval = BQ27XXX_MANUFACTURER; break; default: return -EINVAL; } return ret; }
void bat_monitor_work_func(struct work_struct *work) { struct bq27541_info *di = container_of(work, struct bq27541_info, bat_monitor_work.work); int err = 0; int new_value=0; int change=0; //For dead battery if(di->err_count>=15){ printk("bat:%s get i2c error\n",__func__); err=bq27x00_battery_voltage(di,&new_value); if (err){ queue_delayed_work(bat_work_queue,&di->bat_monitor_work, msecs_to_jiffies(10000 * 1)); blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_I2C_ERROR, NULL); di->health = POWER_SUPPLY_HEALTH_UNKNOWN; power_supply_changed(&di->bat); }else{//dead battery is wake up printk("bat:%s dead battery is wake up\n",__func__); di->err_count=0; queue_delayed_work(bat_work_queue,&di->bat_monitor_work,0); blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_I2C_NORMAL, NULL); di->health = POWER_SUPPLY_HEALTH_GOOD; power_supply_changed(&di->bat); } }else{ /* * We query the four most important variables frequently: * * temperature, voltage, capacity, status * * These four are used by various code in upper layers for * power management. The rest of the variables are not that * important or do not change much over time so we do not * need to query them too often */ if (bq27x00_battery_temperature(di, &new_value)) { di->err_count++; } else { if (new_value != di->temp) { di->temp = new_value; change = 1; bat_temp_charge_protect(di); } } if (bq27x00_battery_voltage(di, &new_value)) { di->err_count++; } else { if (new_value != di->voltage) { di->voltage = new_value; change = 1; //Low battery protection //If android with weak battery has some problem and not be shutdown then driver need to turn off the system. if((di->voltage <= HARD_LOW_VOLTAGE_THRESHOLD) && (di->status==POWER_SUPPLY_STATUS_DISCHARGING)) blocking_notifier_call_chain(¬ifier_list, EVENT_WEAK_BATTERY, NULL); } } if (bq27x00_battery_rsoc(di, &new_value)) { di->err_count++; } else { if (new_value != di->capacity) { di->capacity = new_value; change = 1; //Recharge event if((di->status==POWER_SUPPLY_STATUS_NOT_CHARGING) && (di->capacity<=RECHARGE_THRESHOLD)) blocking_notifier_call_chain(¬ifier_list, EVENT_RECHARGE_BATTERY, NULL); } } if (bq27x00_battery_status(di, &new_value)) { di->err_count++; } else { if (new_value!=di->status) { di->status = new_value; change = 1; //Full charge protectition event if (di->status == POWER_SUPPLY_STATUS_FULL) blocking_notifier_call_chain(¬ifier_list, EVENT_FULL_BATTERY, NULL); } } /* * Average current is also required to be * queried frequently for factory testing */ if (bq27x00_battery_current(di, &new_value)){ di->err_count++; } else { if (new_value != di->current_avg) { di->current_avg=new_value; change = 1; } } if (++di->long_count != BQ27541_LONG_COUNT) { /* Done with the important ones, skip the rest for now */ goto update_status; } else { di->long_count = 0; } new_value=twl_get_batntc(); if(new_value!=di->ntc_temp){ if((di->ntc_temp==0) && (new_value>0)) blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_NTC_NORMAL, NULL); di->ntc_temp=new_value; if(di->ntc_temp==0) blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_NTC_ZERO, NULL); } bq27x00_read(REG_FULL_AVAILABLE_CHARGE, &g_full_available_capacity, 0, di); if (bq27x00_battery_health(di, &new_value)) { di->err_count++; } else { if (new_value != di->health) { di->health = new_value; change = 1; } } /* Query TimeToEmpty() register */ if (bq27x00_battery_time_to_empty(di, &new_value)) { di->err_count++; } else if (new_value != di->time_to_empty) { di->time_to_empty = new_value; change = 1; } /* Query TimeToFull() register */ if (bq27x00_battery_time_to_full(di, &new_value)) { di->err_count++; } else if (new_value != di->time_to_full) { di->time_to_full = new_value; change = 1; } /* Query CycleCount() register */ if (bq27x00_battery_cycle_count(di, &new_value)) { di->err_count++; } else if (new_value != di->cycle_count) { di->cycle_count = new_value; change = 1; } /* Query AveragePower() register */ if (bq27x00_battery_average_power(di, &new_value)) { di->err_count++; } else if (new_value != di->average_power) { di->average_power = new_value; change = 1; } /* Query AvailableEnergy() register */ if (bq27x00_battery_available_energy(di, &new_value)) { di->err_count++; } else if (new_value != di->available_energy) { di->available_energy = new_value; change = 1; } /* Query RemainingCapacity() register */ if (bq27x00_battery_remaining_charge(di, &new_value)) { di->err_count++; } else if (new_value != di->remaining_charge) { di->remaining_charge = new_value; change = 1; } /* Query FullChargeCapacity() register */ if (bq27x00_battery_full_charge(di, &new_value)) { di->err_count++; } else if (new_value != di->full_charge) { di->full_charge = new_value; change = 1; } /* Query FullAvailableCapacity() register */ if (bq27x00_battery_full_charge_uncompensated(di, &new_value)) { di->err_count++; } else if (new_value != di->full_charge_uncompensated) { di->full_charge_uncompensated = new_value; change = 1; } if (++di->manufacturer_id_read_count != 2) { goto update_status; } else { di->manufacturer_id_read_count = 0; } /* Check for manufacturer ID every minute */ new_value = check_manufacturer(di); if (new_value != di->manufacturer){ di->manufacturer = new_value; change = 1; if (di->manufacturer >= 0) blocking_notifier_call_chain(¬ifier_list, EVENT_RECOGNIZE_BATTERY, NULL); if (di->manufacturer == NOT_RECOGNIZE) blocking_notifier_call_chain(¬ifier_list, EVENT_NOT_RECOGNIZE_BATTERY, NULL); if (di->manufacturer == UNKNOW) blocking_notifier_call_chain(¬ifier_list, EVENT_UNKNOW_BATTERY, NULL); } update_status: if (change) { power_supply_changed(&di->bat); // LED function u8 value = 0; if ((di->disable_led == 0) && !twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &value, 0x03)) { if ((di->status == POWER_SUPPLY_STATUS_CHARGING) && (value & (1 << 2))) { if(di->capacity < 90) { /* * Battery being charged, capacity < 90%: Amber LED */ omap4430_green_led_set(NULL, 0); omap4430_orange_led_set(NULL, 255); } else { /* * Battery being charged, capacity >= 90%: Green LED */ omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); } } else if (di->status == POWER_SUPPLY_STATUS_FULL) { if (value & (1 << 2)) { /* Set to green if connected to USB */ omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); } else { omap4430_green_led_set(NULL, 0); omap4430_orange_led_set(NULL, 0); } } } } if(di->err_count>=15){ printk("bat:%s get i2c error\n",__func__); queue_delayed_work(bat_work_queue,&di->bat_monitor_work, msecs_to_jiffies(10000 * 1)); }else queue_delayed_work(bat_work_queue,&di->bat_monitor_work, msecs_to_jiffies(5000 * 1)); } }