/* * Return the battery average current in µA * Note that current can be negative signed as well * Or 0 if something fails. */ static int bq27x00_battery_current(struct bq27x00_device_info *di, union power_supply_propval *val) { int curr; int flags; curr = bq27x00_read(di, BQ27x00_REG_AI, false); if (curr < 0) { dev_err(di->dev, "error reading current\n"); return curr; } if (bq27xxx_is_chip_version_higher(di)) { /* bq27500 returns signed value */ val->intval = (int)((s16)curr) * 1000; } else { flags = bq27x00_read(di, BQ27x00_REG_FLAGS, false); if (flags & BQ27000_FLAG_CHGS) { dev_dbg(di->dev, "negative current!\n"); curr = -curr; } val->intval = curr * 3570 / BQ27000_RS; } return 0; }
/* * Return the battery Initial last measured discharge in µAh * Or < 0 if something fails. */ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) { int ilmd; if (bq27xxx_is_chip_version_higher(di)) { if (di->chip == BQ27425) ilmd = bq27x00_read(di, BQ27425_REG_DCAP, false); else if (di->chip == BQ27510) ilmd = bq27x00_read(di, BQ27510_REG_DCAP, false); else ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); } else { ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); } if (ilmd < 0) { dev_dbg(di->dev, "error reading initial last measured discharge\n"); return ilmd; } if (bq27xxx_is_chip_version_higher(di)) ilmd *= 1000; else ilmd = ilmd * 256 * 3570 / BQ27000_RS; return ilmd; }
int bq27x00_battery_status(struct bq27541_info *di,int* value) { int flags = 0; int curr = 0; int ret; ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di); if (ret < 0) { dev_err(di->dev, "error reading flags\n"); return ret; } if (flags & BQ27500_FLAG_FC) *value = POWER_SUPPLY_STATUS_FULL; else if (flags & BQ27500_FLAG_DSC) *value = POWER_SUPPLY_STATUS_DISCHARGING; else{ ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di); if (ret < 0) { dev_err(di->dev, "error reading flags\n"); return ret; } if(curr==0){ *value = POWER_SUPPLY_STATUS_NOT_CHARGING; }else if(curr>0){ *value = POWER_SUPPLY_STATUS_CHARGING; } } return ret; }
/* * Return the battery Cycle count total * Or < 0 if something fails. */ static int bq27x00_battery_read_cyct(struct bq27x00_device_info *di) { int cyct; if (di->chip == BQ27510) cyct = bq27x00_read(di, BQ27510_REG_CYCT, false); else cyct = bq27x00_read(di, BQ27x00_REG_CYCT, false); if (cyct < 0) dev_err(di->dev, "error reading cycle count total\n"); return cyct; }
/* * Return the battery Relative State-of-Charge * Or < 0 if something fails. */ static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di) { int rsoc; if (di->chip == BQ27500) rsoc = bq27x00_read(di, BQ27500_REG_SOC, false); else rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true); if (rsoc < 0) dev_dbg(di->dev, "error reading relative State-of-Charge\n"); return rsoc; }
/* * Read flag register. * Return < 0 if something fails. */ static int bq27x00_battery_read_health(struct bq27x00_device_info *di) { int tval; tval = bq27x00_read(di, BQ27x00_REG_FLAGS, false); if (tval < 0) { dev_err(di->dev, "error reading flag register:%d\n", tval); return tval; } if (di->chip == BQ27500) { if (tval & BQ27500_FLAG_SOCF) tval = POWER_SUPPLY_HEALTH_DEAD; else if (tval & BQ27500_FLAG_OTC) tval = POWER_SUPPLY_HEALTH_OVERHEAT; else tval = POWER_SUPPLY_HEALTH_GOOD; return tval; } else if (di->chip == BQ27510) { if (tval & BQ27500_FLAG_OTC) return POWER_SUPPLY_HEALTH_OVERHEAT; return POWER_SUPPLY_HEALTH_GOOD; } else { if (tval & BQ27000_FLAG_EDV1) tval = POWER_SUPPLY_HEALTH_DEAD; else tval = POWER_SUPPLY_HEALTH_GOOD; return tval; } return -1; }
/* * Return the battery State-of-Charge for bq34z100 * Or < 0 if something fails. */ static int bq27x00_battery_read_soc(struct bq27x00_device_info *di) { int soc; if (di->chip == BQ27500) soc = bq27x00_read(di, BQ27500_REG_SOC, false); else if (di->chip == BQ27425) soc = bq27x00_read(di, BQ27425_REG_SOC, false); else soc = bq27x00_read(di, BQ27x00_REG_SOC, false); if (soc < 0) dev_dbg(di->dev, "error reading State-of-Charge\n"); return soc; }
static int __devinit bq27541_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bq27541_info *di; int ret; int error; printk(KERN_INFO "%s\n",__func__); di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) { return -ENOMEM; } di->bat_client = client; di->dev = &client->dev; di->bat.type = POWER_SUPPLY_TYPE_BATTERY; di->bat.name = "battery"; di->bat.properties = bq27x00_battery_props; di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); di->bat.get_property = bq27x00_get_property; di->bat.external_power_changed = NULL; di->temp = 0; di->ntc_temp = 0; di->voltage = 0; di->current_avg = 0; di->capacity = 0; di->status = 0; di->sec = 0; /*Manufacturer id check function */ di->manufacturer = UNKNOW; di->battery_polling = 1;fake_temp=-990;fake_full_available_capacity=0; di->disable_led=0; di->health = POWER_SUPPLY_HEALTH_GOOD; i2c_set_clientdata(client, di); ret = power_supply_register(di->dev, &di->bat); if (ret) { dev_dbg(di->dev,"failed to register battery\n"); //goto bk_batt_failed; } /*Manufacturer id check function */ di->manufacturer=check_manufacturer(di); bq27x00_read(REG_FULL_AVAILABLE_CHARGE, &g_full_available_capacity, 0, di); create_bq_procfs(di); #ifdef BAT_LOG INIT_DELAYED_WORK_DEFERRABLE(&di->bat_log_work,bat_log_work_func); #endif INIT_DELAYED_WORK_DEFERRABLE(&di->bat_monitor_work,bat_monitor_work_func); queue_delayed_work(bat_work_queue,&di->bat_monitor_work, msecs_to_jiffies(1000 * 1)); BLOCKING_INIT_NOTIFIER_HEAD(¬ifier_list); /* Create a sysfs node */ error = sysfs_create_group(&di->dev->kobj, &bq_attr_grp); if (error) { dev_dbg(di->dev,"could not create sysfs_create_group\n"); return -1; } return 0; }
static void bq27x00_update(struct bq27x00_device_info *di) { struct bq27x00_reg_cache cache = {0, }; bool is_bq27500 = di->chip == BQ27500; bool is_bq27425 = di->chip == BQ27425; cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500); if ((cache.flags & 0xff) == 0xff) /* read error */ cache.flags = -1; if (cache.flags >= 0) { if (!is_bq27500 && !is_bq27425 && (cache.flags & BQ27000_FLAG_CI)) { dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n"); cache.capacity = -ENODATA; cache.energy = -ENODATA; cache.time_to_empty = -ENODATA; cache.time_to_empty_avg = -ENODATA; cache.time_to_full = -ENODATA; cache.charge_full = -ENODATA; cache.health = -ENODATA; } else { cache.capacity = bq27x00_battery_read_rsoc(di); if (!is_bq27425) { cache.energy = bq27x00_battery_read_energy(di); cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); } cache.charge_full = bq27x00_battery_read_lmd(di); cache.health = bq27x00_battery_read_health(di); } cache.temperature = bq27x00_battery_read_temperature(di); if (!is_bq27425) cache.cycle_count = bq27x00_battery_read_cyct(di); cache.power_avg = bq27x00_battery_read_pwr_avg(di, BQ27x00_POWER_AVG); /* We only have to read charge design full once */ if (di->charge_design_full <= 0) di->charge_design_full = bq27x00_battery_read_ilmd(di); } if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) { di->cache = cache; power_supply_changed(&di->bat); } di->last_update = jiffies; }
static ssize_t time_to_empty_at_constant_power_show(struct device *dev, struct device_attribute *attr,char *buf) { struct bq27541_info *di = i2c_get_clientdata(to_i2c_client(dev)); int ret=0; int minute=0; ret = bq27x00_read(REG_TIME_TO_EMPTYT_AT_CONSTANT_POWER, &minute, 0, di); if (ret) { return 0; } return sprintf(buf, "%d minute\n", minute); }
static ssize_t max_load_time_to_empty_show(struct device *dev, struct device_attribute *attr,char *buf) { struct bq27541_info *di = i2c_get_clientdata(to_i2c_client(dev)); int ret=0; int minute=0; ret = bq27x00_read(REG_MAX_LOAD_TIME_TO_EMPTY, &minute, 0, di); if (ret) { return 0; } return sprintf(buf, "%d minute\n", minute); }
static ssize_t nominal_available_capacity_show(struct device *dev, struct device_attribute *attr,char *buf) { struct bq27541_info *di = i2c_get_clientdata(to_i2c_client(dev)); int ret=0; int capacity=0; ret = bq27x00_read(REG_NOMINAL_AVAILABLE_CAPACITY, &capacity, 0, di); if (ret) { return 0; } return sprintf(buf, "%d mAh\n", capacity); }
static ssize_t at_rate_time_to_empty_show(struct device *dev, struct device_attribute *attr,char *buf) { struct bq27541_info *di = i2c_get_clientdata(to_i2c_client(dev)); int ret=0; int time=0; ret = bq27x00_read(REG_AT_RATE_TIME_TO_EMPTY, &time, 0, di); if (ret < 0) { return 0; } return sprintf(buf, "%d minute\n", time); }
/* * Return the battery Voltage in milivolts * Or < 0 if something fails. */ int bq27x00_battery_voltage(struct bq27541_info *di,int* value) { int ret=0; int volt = 0; ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di); if (ret) { dev_err(di->dev, "error reading voltage\n"); return ret; } *value =volt * 1000; return ret; }
/* * Return the battery Nominal available capaciy in µAh * Or < 0 if something fails. */ static inline int bq27x00_battery_read_nac(struct bq27x00_device_info *di) { int flags; bool is_bq27500 = di->chip == BQ27500; bool is_higher = bq27xxx_is_chip_version_higher(di); flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500); if (flags >= 0 && !is_higher && (flags & BQ27000_FLAG_CI)) return -ENODATA; return bq27x00_battery_read_charge(di, BQ27x00_REG_NAC); }
static ssize_t max_load_current_show(struct device *dev, struct device_attribute *attr,char *buf) { struct bq27541_info *di = i2c_get_clientdata(to_i2c_client(dev)); int ret=0; int curr=0; ret = bq27x00_read(REG_MAX_LOAD_CURRENT, &curr, 0, di); if (ret) { return 0; } /* bq27500 returns signed value */ curr = (int)(s16)curr; return sprintf(buf, "%d mA\n", curr); }
static ssize_t at_rate_show(struct device *dev, struct device_attribute *attr,char *buf) { struct bq27541_info *di = i2c_get_clientdata(to_i2c_client(dev)); int ret=0; int at_rate=0; ret = bq27x00_read(REG_AT_RATE, &at_rate, 0, di); if (ret) { return 0; } /* bq27500 returns signed value */ at_rate = (int)(s16)at_rate; return sprintf(buf, "%d mA\n", at_rate); }
/* * Return the battery Relative State-of-Charge * Or < 0 if something fails. */ int bq27x00_battery_rsoc(struct bq27541_info *di,int* value) { int ret=0; int rsoc=0; ret = bq27x00_read(BQ27500_REG_SOC, &rsoc, 0, di); if (ret < 0) { dev_err(di->dev, "error reading rsoc\n"); return ret; } *value=rsoc; return ret; }
/* * Return the battery temperature in tenths of degree Celsius * Or < 0 if something fails. */ int bq27x00_battery_temperature(struct bq27541_info *di,int* value) { int ret=0; int temp = 0; ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);//0.1K if (ret) { dev_err(di->dev, "error reading temperature\n"); return ret; } //Kelvin to Celsius °C = K − 273.15 *value=temp - 2731; return ret; }
/* * Return the battery Voltage in millivolts * Or < 0 if something fails. */ static int bq27x00_battery_voltage(struct bq27x00_device_info *di, union power_supply_propval *val) { int volt; volt = bq27x00_read(di, BQ27x00_REG_VOLT, false); if (volt < 0) { dev_err(di->dev, "error reading voltage\n"); return volt; } val->intval = volt * 1000; return 0; }
/* * Return the battery temperature in tenths of degree Kelvin * Or < 0 if something fails. */ static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di) { int temp; temp = bq27x00_read(di, BQ27x00_REG_TEMP, false); if (temp < 0) { dev_err(di->dev, "error reading temperature\n"); return temp; } if (!bq27xxx_is_chip_version_higher(di)) temp = 5 * temp / 2; return temp; }
/* * Read a power avg register. * Return < 0 if something fails. */ static int bq27x00_battery_read_pwr_avg(struct bq27x00_device_info *di, u8 reg) { int tval; tval = bq27x00_read(di, reg, false); if (tval < 0) { dev_err(di->dev, "error reading power avg rgister %02x: %d\n", reg, tval); return tval; } if (di->chip == BQ27500) return tval; else return (tval * BQ27x00_POWER_CONSTANT) / BQ27000_RS; }
/* * Read a time register. * Return < 0 if something fails. */ static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg) { int tval; tval = bq27x00_read(di, reg, false); if (tval < 0) { dev_dbg(di->dev, "error reading time register %02x: %d\n", reg, tval); return tval; } if (tval == 65535) return -ENODATA; return tval * 60; }
/* * Return the battery average current(milliamp) * Note that current can be negative signed as well * Or 0 if something fails. */ int bq27x00_battery_current(struct bq27541_info *di,int* value) { int ret=0; int curr = 0; ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di); if (ret) { dev_err(di->dev, "error reading current\n"); return ret; } /* bq27500 returns signed value */ curr = (int)(s16)curr; *value=curr * 1000; return ret; }
/* * Return the battery temperature in tenths of degree Celsius * Or < 0 if something fails. */ static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di) { int temp; temp = bq27x00_read(di, BQ27x00_REG_TEMP, false); if (temp < 0) { dev_err(di->dev, "error reading temperature\n"); return temp; } if (di->chip == BQ27500) temp -= 2731; else temp = ((temp * 5) - 5463) / 2; return temp; }
/* * Return the battery Available energy in µWh * Or < 0 if something fails. */ static int bq27x00_battery_read_energy(struct bq27x00_device_info *di) { int ae; ae = bq27x00_read(di, BQ27x00_REG_AE, false); if (ae < 0) { dev_dbg(di->dev, "error reading available energy\n"); return ae; } if (di->chip == BQ27500) ae *= 1000; else ae = ae * 29200 / BQ27000_RS; return ae; }
static int bq27x00_battery_cycle_count(struct bq27541_info *di, unsigned int *value) { int ret = -1, count = 0; *value = 0; ret = bq27x00_read(REG_CYCLE_COUNT, &count, 0, di); if (ret) { dev_err(di->dev, "error reading cycle count\n"); return ret; } *value = (unsigned int)count; return 0; }
/* * Return a battery charge value in µAh * Or < 0 if something fails. */ static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg) { int charge; charge = bq27x00_read(di, reg, false); if (charge < 0) { dev_dbg(di->dev, "error reading charge register %02x: %d\n", reg, charge); return charge; } if (bq27xxx_is_chip_version_higher(di)) charge *= 1000; else charge = charge * 3570 / BQ27000_RS; return charge; }
static int bq27x00_battery_full_charge_uncompensated(struct bq27541_info *di, unsigned int *value) { int ret = -1, charge = 0; *value = 0; ret = bq27x00_read(REG_FULL_AVAILABLE_CHARGE, &charge, 0, di); if (ret) { dev_err(di->dev, "error reading full charge (uncompensated)\n"); return ret; } /* Convert mAh to uAh */ *value = (unsigned int)(charge * 1000); return 0; }
static int bq27x00_battery_remaining_charge(struct bq27541_info *di, unsigned int *value) { int ret = -1, charge = 0; *value = 0; ret = bq27x00_read(REG_REMAINING_CHARGE, &charge, 0, di); if (ret) { dev_err(di->dev, "error reading remaining capacity\n"); return ret; } /* Convert mAh to uAh */ *value = (unsigned int)(charge * 1000); return 0; }