int time_to_empty_avg;
int time_to_full;
int charge_full;
- int cycle_count;
- int capacity;
+ int charge_now;
int energy;
int flags;
+
+ int voltage;
+ int curr;
};
struct bq27x00_device_info {
return tval * 60;
}
+static int bq27x00_time(int tval)
+{
+ if (tval == 65535)
+ return -ENODATA;
+
+ return tval * 60;
+}
+
+static int bq27x00_read_i2c_n(struct bq27x00_device_info *di, u8 *data,
+ size_t len, u8 start);
+
static void bq27x00_update(struct bq27x00_device_info *di)
{
struct bq27x00_reg_cache cache = {0, };
bool is_bq27500 = di->chip == BQ27500;
+ u8 state[0x28];
int flags_changed;
+ int ret;
- cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500);
- if (cache.flags >= 0) {
- if (!is_bq27500 && (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;
- } else {
- cache.capacity = bq27x00_battery_read_rsoc(di);
- 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.temperature = bq27x00_battery_read_temperature(di);
- cache.cycle_count = bq27x00_battery_read_cyct(di);
-
- /* We only have to read charge design full once */
- if (di->charge_design_full <= 0)
- di->charge_design_full = bq27x00_battery_read_ilmd(di);
+ /* pandora hack */
+ WARN_ON_ONCE(!is_bq27500);
+ (void)bq27x00_battery_read_energy;
+ (void)bq27x00_battery_read_temperature;
+ (void)bq27x00_battery_read_time;
+
+ /* reading reserved field breaks subsequent reads,
+ * so can't read everything in one go :( */
+ ret = bq27x00_read_i2c_n(di, state + 6, sizeof(state) - 6, 6);
+ if (ret < 0) {
+ dev_err(di->dev, "error reading state: %d\n", ret);
+ return;
}
+ cache.flags = get_unaligned_le16(&state[BQ27x00_REG_FLAGS]);
+ cache.energy = get_unaligned_le16(&state[BQ27x00_REG_AE]) * 1000;
+ cache.time_to_empty = get_unaligned_le16(&state[BQ27x00_REG_TTE]);
+ cache.time_to_empty = bq27x00_time(cache.time_to_empty);
+ cache.time_to_empty_avg = get_unaligned_le16(&state[BQ27x00_REG_TTECP]);
+ cache.time_to_empty_avg = bq27x00_time(cache.time_to_empty_avg);
+ cache.time_to_full = get_unaligned_le16(&state[BQ27x00_REG_TTF]);
+ cache.time_to_full = bq27x00_time(cache.time_to_full);
+ cache.charge_full = get_unaligned_le16(&state[BQ27x00_REG_LMD]) * 1000;
+ cache.charge_now = get_unaligned_le16(&state[BQ27x00_REG_NAC]) * 1000;
+ cache.temperature = get_unaligned_le16(&state[BQ27x00_REG_TEMP]);
+ cache.voltage = get_unaligned_le16(&state[BQ27x00_REG_VOLT]) * 1000;
+ cache.curr = (s16)get_unaligned_le16(&state[BQ27x00_REG_AI]) * 1000;
+
+ /* We only have to read charge design full once */
+ if (di->charge_design_full <= 0)
+ di->charge_design_full = bq27x00_battery_read_ilmd(di);
+
/*
* On bq27500, DSG is not set on discharge with very low currents,
* so check AI to not misreport that we are charging in status query
*/
if (is_bq27500 && !(cache.flags & BQ27500_FLAG_DSC)) {
- int curr = bq27x00_read(di, BQ27x00_REG_AI, false);
- if ((s16)curr <= 0)
+ if (cache.curr <= 0)
cache.flags |= BQ27500_FLAG_DSC;
}
ret = bq27x00_battery_status(di, val);
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- ret = bq27x00_battery_voltage(di, val);
+ if (time_is_before_jiffies(di->last_update + HZ))
+ ret = bq27x00_battery_voltage(di, val);
+ else
+ ret = bq27x00_simple_value(di->cache.voltage, 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);
+ ret = 0;
+ if (time_is_before_jiffies(di->last_update + HZ))
+ ret = bq27x00_battery_current(di, val);
+ else
+ val->intval = di->cache.curr;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- ret = bq27x00_simple_value(di->cache.capacity, val);
+ ret = bq27x00_simple_value(bq27x00_battery_read_rsoc(di), val);
break;
case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
ret = bq27x00_battery_capacity_level(di, val);
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
case POWER_SUPPLY_PROP_CHARGE_NOW:
- ret = bq27x00_simple_value(bq27x00_battery_read_nac(di), val);
+ ret = bq27x00_simple_value(di->cache.charge_now, val);
break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
ret = bq27x00_simple_value(di->cache.charge_full, val);
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);
+ ret = bq27x00_simple_value(bq27x00_battery_read_cyct(di), val);
break;
case POWER_SUPPLY_PROP_ENERGY_NOW:
ret = bq27x00_simple_value(di->cache.energy, val);
return ret;
}
+static int bq27x00_read_i2c_n(struct bq27x00_device_info *di, u8 *data,
+ size_t len, u8 start)
+{
+ struct i2c_client *client = to_i2c_client(di->dev);
+ struct i2c_msg msg[2];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].buf = &start;
+ msg[0].len = sizeof(start);
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = data;
+ msg[1].len = len;
+
+ return i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+}
+
static int bq27x00_battery_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{