diff options
Diffstat (limited to 'drivers/power/bq27x00_battery.c')
-rw-r--r-- | drivers/power/bq27x00_battery.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index f5d6d379f2fb..5657990b7ace 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ | 51 | #define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ |
52 | #define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ | 52 | #define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ |
53 | #define BQ27x00_REG_AE 0x22 /* Available energy */ | 53 | #define BQ27x00_REG_AE 0x22 /* Available energy */ |
54 | #define BQ27x00_POWER_AVG 0x24 | ||
54 | 55 | ||
55 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ | 56 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ |
56 | #define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ | 57 | #define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ |
@@ -66,8 +67,10 @@ | |||
66 | #define BQ27500_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ | 67 | #define BQ27500_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ |
67 | #define BQ27500_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ | 68 | #define BQ27500_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ |
68 | #define BQ27500_FLAG_FC BIT(9) | 69 | #define BQ27500_FLAG_FC BIT(9) |
70 | #define BQ27500_FLAG_OTC BIT(15) | ||
69 | 71 | ||
70 | #define BQ27000_RS 20 /* Resistor sense */ | 72 | #define BQ27000_RS 20 /* Resistor sense */ |
73 | #define BQ27x00_POWER_CONSTANT (256 * 29200 / 1000) | ||
71 | 74 | ||
72 | struct bq27x00_device_info; | 75 | struct bq27x00_device_info; |
73 | struct bq27x00_access_methods { | 76 | struct bq27x00_access_methods { |
@@ -86,6 +89,8 @@ struct bq27x00_reg_cache { | |||
86 | int capacity; | 89 | int capacity; |
87 | int energy; | 90 | int energy; |
88 | int flags; | 91 | int flags; |
92 | int power_avg; | ||
93 | int health; | ||
89 | }; | 94 | }; |
90 | 95 | ||
91 | struct bq27x00_device_info { | 96 | struct bq27x00_device_info { |
@@ -123,6 +128,8 @@ static enum power_supply_property bq27x00_battery_props[] = { | |||
123 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | 128 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, |
124 | POWER_SUPPLY_PROP_CYCLE_COUNT, | 129 | POWER_SUPPLY_PROP_CYCLE_COUNT, |
125 | POWER_SUPPLY_PROP_ENERGY_NOW, | 130 | POWER_SUPPLY_PROP_ENERGY_NOW, |
131 | POWER_SUPPLY_PROP_POWER_AVG, | ||
132 | POWER_SUPPLY_PROP_HEALTH, | ||
126 | }; | 133 | }; |
127 | 134 | ||
128 | static unsigned int poll_interval = 360; | 135 | static unsigned int poll_interval = 360; |
@@ -306,6 +313,60 @@ static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg) | |||
306 | return tval * 60; | 313 | return tval * 60; |
307 | } | 314 | } |
308 | 315 | ||
316 | /* | ||
317 | * Read a power avg register. | ||
318 | * Return < 0 if something fails. | ||
319 | */ | ||
320 | static int bq27x00_battery_read_pwr_avg(struct bq27x00_device_info *di, u8 reg) | ||
321 | { | ||
322 | int tval; | ||
323 | |||
324 | tval = bq27x00_read(di, reg, false); | ||
325 | if (tval < 0) { | ||
326 | dev_err(di->dev, "error reading power avg rgister %02x: %d\n", | ||
327 | reg, tval); | ||
328 | return tval; | ||
329 | } | ||
330 | |||
331 | if (di->chip == BQ27500) | ||
332 | return tval; | ||
333 | else | ||
334 | return (tval * BQ27x00_POWER_CONSTANT) / BQ27000_RS; | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * Read flag register. | ||
339 | * Return < 0 if something fails. | ||
340 | */ | ||
341 | static int bq27x00_battery_read_health(struct bq27x00_device_info *di) | ||
342 | { | ||
343 | int tval; | ||
344 | |||
345 | tval = bq27x00_read(di, BQ27x00_REG_FLAGS, false); | ||
346 | if (tval < 0) { | ||
347 | dev_err(di->dev, "error reading flag register:%d\n", tval); | ||
348 | return tval; | ||
349 | } | ||
350 | |||
351 | if ((di->chip == BQ27500)) { | ||
352 | if (tval & BQ27500_FLAG_SOCF) | ||
353 | tval = POWER_SUPPLY_HEALTH_DEAD; | ||
354 | else if (tval & BQ27500_FLAG_OTC) | ||
355 | tval = POWER_SUPPLY_HEALTH_OVERHEAT; | ||
356 | else | ||
357 | tval = POWER_SUPPLY_HEALTH_GOOD; | ||
358 | return tval; | ||
359 | } else { | ||
360 | if (tval & BQ27000_FLAG_EDV1) | ||
361 | tval = POWER_SUPPLY_HEALTH_DEAD; | ||
362 | else | ||
363 | tval = POWER_SUPPLY_HEALTH_GOOD; | ||
364 | return tval; | ||
365 | } | ||
366 | |||
367 | return -1; | ||
368 | } | ||
369 | |||
309 | static void bq27x00_update(struct bq27x00_device_info *di) | 370 | static void bq27x00_update(struct bq27x00_device_info *di) |
310 | { | 371 | { |
311 | struct bq27x00_reg_cache cache = {0, }; | 372 | struct bq27x00_reg_cache cache = {0, }; |
@@ -321,6 +382,7 @@ static void bq27x00_update(struct bq27x00_device_info *di) | |||
321 | cache.time_to_empty_avg = -ENODATA; | 382 | cache.time_to_empty_avg = -ENODATA; |
322 | cache.time_to_full = -ENODATA; | 383 | cache.time_to_full = -ENODATA; |
323 | cache.charge_full = -ENODATA; | 384 | cache.charge_full = -ENODATA; |
385 | cache.health = -ENODATA; | ||
324 | } else { | 386 | } else { |
325 | cache.capacity = bq27x00_battery_read_rsoc(di); | 387 | cache.capacity = bq27x00_battery_read_rsoc(di); |
326 | cache.energy = bq27x00_battery_read_energy(di); | 388 | cache.energy = bq27x00_battery_read_energy(di); |
@@ -328,9 +390,12 @@ static void bq27x00_update(struct bq27x00_device_info *di) | |||
328 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); | 390 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); |
329 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); | 391 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); |
330 | cache.charge_full = bq27x00_battery_read_lmd(di); | 392 | cache.charge_full = bq27x00_battery_read_lmd(di); |
393 | cache.health = bq27x00_battery_read_health(di); | ||
331 | } | 394 | } |
332 | cache.temperature = bq27x00_battery_read_temperature(di); | 395 | cache.temperature = bq27x00_battery_read_temperature(di); |
333 | cache.cycle_count = bq27x00_battery_read_cyct(di); | 396 | cache.cycle_count = bq27x00_battery_read_cyct(di); |
397 | cache.power_avg = | ||
398 | bq27x00_battery_read_pwr_avg(di, BQ27x00_POWER_AVG); | ||
334 | 399 | ||
335 | /* We only have to read charge design full once */ | 400 | /* We only have to read charge design full once */ |
336 | if (di->charge_design_full <= 0) | 401 | if (di->charge_design_full <= 0) |
@@ -550,6 +615,12 @@ static int bq27x00_battery_get_property(struct power_supply *psy, | |||
550 | case POWER_SUPPLY_PROP_ENERGY_NOW: | 615 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
551 | ret = bq27x00_simple_value(di->cache.energy, val); | 616 | ret = bq27x00_simple_value(di->cache.energy, val); |
552 | break; | 617 | break; |
618 | case POWER_SUPPLY_PROP_POWER_AVG: | ||
619 | ret = bq27x00_simple_value(di->cache.power_avg, val); | ||
620 | break; | ||
621 | case POWER_SUPPLY_PROP_HEALTH: | ||
622 | ret = bq27x00_simple_value(di->cache.health, val); | ||
623 | break; | ||
553 | default: | 624 | default: |
554 | return -EINVAL; | 625 | return -EINVAL; |
555 | } | 626 | } |