diff --git a/drivers/power/bq27541_battery.c b/drivers/power/bq27541_battery.c index e0844013a9dc..7e81921963c8 100644 --- a/drivers/power/bq27541_battery.c +++ b/drivers/power/bq27541_battery.c @@ -16,6 +16,7 @@ * more details. */ + #include #include #include @@ -28,11 +29,12 @@ #include #include #include +#include #include #include #include -#include +#include #define SMBUS_RETRY (0) #define GPIOPIN_LOW_BATTERY_DETECT 29 @@ -59,7 +61,6 @@ #define THERMAL_RULE1 1 #define THERMAL_RULE2 2 - /* Debug Message */ #define BAT_NOTICE(format, arg...) \ printk(KERN_NOTICE "%s " format , __FUNCTION__ , ## arg) @@ -109,7 +110,16 @@ enum { REG_TIME_TO_FULL, REG_STATUS, REG_CAPACITY, - REG_SERIAL_NUMBER, + //REG_SERIAL_NUMBER, + REG_CHARGE_NOW, + REG_CHARGE_UCOMP, + REG_CHARGE_FULL, + REG_CHARGE_DESIGN, + REG_ENERGY, + REG_CHARGE_COUNTER, + REG_POWER, + REG_CYCLE, + REG_MAX }; @@ -137,6 +147,14 @@ static struct bq27541_device_data { [REG_TIME_TO_FULL] = BQ27541_DATA(TIME_TO_FULL_AVG, 0x18, 0, 65535), [REG_STATUS] = BQ27541_DATA(STATUS, 0x0a, 0, 65535), [REG_CAPACITY] = BQ27541_DATA(CAPACITY, 0x2c, 0, 100), + [REG_CHARGE_NOW] = BQ27541_DATA(CHARGE_NOW, 0x10, 0, 65535), + [REG_CHARGE_UCOMP] = BQ27541_DATA(CHARGE_AVG, 0x0c, 0, 65535), + [REG_CHARGE_FULL] = BQ27541_DATA(CHARGE_FULL, 0x12, 0, 65535), + [REG_CHARGE_DESIGN] = BQ27541_DATA(CHARGE_FULL_DESIGN, 0x3c, 0, 65535), + [REG_ENERGY] = BQ27541_DATA(ENERGY_NOW, 0x22, 0, 65535), + [REG_CHARGE_COUNTER] = BQ27541_DATA(CHARGE_COUNTER, 0x34, -32768, 32767), + [REG_POWER] = BQ27541_DATA(POWER_NOW, 0x24, -32768, 32767), + [REG_CYCLE] = BQ27541_DATA(CYCLE_COUNT, 0x2a, 0, 65535), }; static enum power_supply_property bq27541_properties[] = { @@ -148,6 +166,14 @@ static enum power_supply_property bq27541_properties[] = { POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_AVG, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_POWER_NOW, + POWER_SUPPLY_PROP_CYCLE_COUNT }; unsigned get_cable_status(void) @@ -276,7 +302,7 @@ static struct bq27541_device_info { int old_temperature; bool temp_err; unsigned int prj_id; - spinlock_t lock; + struct mutex lock; } *bq27541_device; static int bq27541_read_i2c(u8 reg, int *rt_value, int b_single) @@ -361,26 +387,6 @@ static const struct attribute_group battery_smbus_group = { .attrs = battery_smbus_attributes, }; -static int bq27541_battery_current(void) -{ - int ret; - int curr = 0; - - ret = bq27541_read_i2c(bq27541_data[REG_CURRENT].addr, &curr, 0); - if (ret) { - BAT_ERR("error reading current ret = %x\n", ret); - return 0; - } - - curr = (s16)curr; - - if (curr >= bq27541_data[REG_CURRENT].min_value && - curr <= bq27541_data[REG_CURRENT].max_value) { - return curr; - } else - return 0; -} - static void battery_status_poll(struct work_struct *work) { struct bq27541_device_info *batt_dev = container_of(work, struct bq27541_device_info, status_poll_work.work); @@ -555,6 +561,42 @@ static int bq27541_get_psp(int reg_offset, enum power_supply_property psp, return -EINVAL; } + if (psp == POWER_SUPPLY_PROP_CHARGE_NOW) { + val->intval = rt_value * 1000; + BAT_NOTICE("charge_now (compensated) = %u uAh\n", val->intval); + } + if (psp == POWER_SUPPLY_PROP_CHARGE_AVG) { + val->intval = rt_value * 1000; + BAT_NOTICE("charge_avg (uncompensated) = %u uAh\n", val->intval); + } + if (psp == POWER_SUPPLY_PROP_CHARGE_FULL) { + val->intval = rt_value * 1000; + BAT_NOTICE("charge_full = %u uAh\n", val->intval); + } + if (psp == POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN) { + val->intval = rt_value * 1000; + BAT_NOTICE("charge_design = %u uAh\n", val->intval); + } + if (psp == POWER_SUPPLY_PROP_ENERGY_NOW) { + val->intval = rt_value * 1000; + BAT_NOTICE("energy_now = %u uWh\n", val->intval); + } + if (psp == POWER_SUPPLY_PROP_CHARGE_COUNTER) { + val->intval = ((s16) rt_value) * 1000; + BAT_NOTICE("charge_counter = %d uWh\n", val->intval); + } + if (psp == POWER_SUPPLY_PROP_POWER_NOW) { + val->intval = ((s16) rt_value) * 1000; + BAT_NOTICE("power_now = %d uW\n", val->intval); + } + if (psp == POWER_SUPPLY_PROP_CYCLE_COUNT) { + val->intval = rt_value; + BAT_NOTICE("cycle count = %u\n", val->intval); + } + if (psp == POWER_SUPPLY_PROP_CURRENT_NOW) { + val->intval = (s16)rt_value; + BAT_NOTICE("current_now = %d mA\n", val->intval); + } if (psp == POWER_SUPPLY_PROP_VOLTAGE_NOW) { if (rt_value >= bq27541_data[REG_VOLTAGE].min_value && rt_value <= bq27541_data[REG_VOLTAGE].max_value) { @@ -613,11 +655,6 @@ static int bq27541_get_psp(int reg_offset, enum power_supply_property psp, bq27541_device->old_temperature = val->intval = ret; BAT_NOTICE("temperature= %d (0.1¢XC)\n", val->intval); } - if (psp == POWER_SUPPLY_PROP_CURRENT_NOW) { - val->intval = bq27541_device->bat_current - = bq27541_battery_current(); - BAT_NOTICE("current = %d mA\n", val->intval); - } return 0; } @@ -723,6 +760,9 @@ static int bq27541_get_property(struct power_supply *psy, union power_supply_propval *val) { u8 count; + + mutex_lock(&bq27541_device->lock); + switch (psp) { case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_HEALTH: @@ -743,28 +783,36 @@ static int bq27541_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_NOW: case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_TEMP: - case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: - case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: case POWER_SUPPLY_PROP_SERIAL_NUMBER: + case POWER_SUPPLY_PROP_CHARGE_NOW: + case POWER_SUPPLY_PROP_CHARGE_AVG: + case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + case POWER_SUPPLY_PROP_ENERGY_NOW: + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + case POWER_SUPPLY_PROP_POWER_NOW: + case POWER_SUPPLY_PROP_CYCLE_COUNT: for (count = 0; count < REG_MAX; count++) { if (psp == bq27541_data[count].psp) break; } if (bq27541_get_psp(count, psp, val)) - return -EINVAL; + goto error; break; default: dev_err(&bq27541_device->client->dev, "%s: INVALID property psp=%u\n", __func__,psp); - return -EINVAL; + goto error; } + mutex_unlock(&bq27541_device->lock); return 0; error: + mutex_unlock(&bq27541_device->lock); return -EINVAL; } @@ -788,6 +836,7 @@ static int bq27541_probe(struct i2c_client *client, bq27541_device->old_temperature = 0xFF; bq27541_device->gpio_low_battery_detect = GPIOPIN_LOW_BATTERY_DETECT; bq27541_device->bat_capacity_zero_count = 0; + mutex_init(&bq27541_device->lock); for (i = 0; i < ARRAY_SIZE(bq27541_supply); i++) { ret = power_supply_register(&client->dev, &bq27541_supply[i]); @@ -805,7 +854,6 @@ static int bq27541_probe(struct i2c_client *client, INIT_DELAYED_WORK(&bq27541_device->low_low_bat_work, low_low_battery_check); cancel_delayed_work(&bq27541_device->status_poll_work); - spin_lock_init(&bq27541_device->lock); wake_lock_init(&bq27541_device->low_battery_wake_lock, WAKE_LOCK_SUSPEND, "low_battery_detection"); wake_lock_init(&bq27541_device->cable_wake_lock, WAKE_LOCK_SUSPEND, "cable_state_changed");