diff options
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/bq27x00_battery.c | 84 |
1 files changed, 69 insertions, 15 deletions
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 5657990b7ace..181ddece5181 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * Datasheets: | 22 | * Datasheets: |
23 | * http://focus.ti.com/docs/prod/folders/print/bq27000.html | 23 | * http://focus.ti.com/docs/prod/folders/print/bq27000.html |
24 | * http://focus.ti.com/docs/prod/folders/print/bq27500.html | 24 | * http://focus.ti.com/docs/prod/folders/print/bq27500.html |
25 | * http://www.ti.com/product/bq27425-g1 | ||
25 | */ | 26 | */ |
26 | 27 | ||
27 | #include <linux/module.h> | 28 | #include <linux/module.h> |
@@ -69,6 +70,10 @@ | |||
69 | #define BQ27500_FLAG_FC BIT(9) | 70 | #define BQ27500_FLAG_FC BIT(9) |
70 | #define BQ27500_FLAG_OTC BIT(15) | 71 | #define BQ27500_FLAG_OTC BIT(15) |
71 | 72 | ||
73 | /* bq27425 register addresses are same as bq27x00 addresses minus 4 */ | ||
74 | #define BQ27425_REG_OFFSET 0x04 | ||
75 | #define BQ27425_REG_SOC 0x18 /* Register address plus offset */ | ||
76 | |||
72 | #define BQ27000_RS 20 /* Resistor sense */ | 77 | #define BQ27000_RS 20 /* Resistor sense */ |
73 | #define BQ27x00_POWER_CONSTANT (256 * 29200 / 1000) | 78 | #define BQ27x00_POWER_CONSTANT (256 * 29200 / 1000) |
74 | 79 | ||
@@ -77,7 +82,7 @@ struct bq27x00_access_methods { | |||
77 | int (*read)(struct bq27x00_device_info *di, u8 reg, bool single); | 82 | int (*read)(struct bq27x00_device_info *di, u8 reg, bool single); |
78 | }; | 83 | }; |
79 | 84 | ||
80 | enum bq27x00_chip { BQ27000, BQ27500 }; | 85 | enum bq27x00_chip { BQ27000, BQ27500, BQ27425}; |
81 | 86 | ||
82 | struct bq27x00_reg_cache { | 87 | struct bq27x00_reg_cache { |
83 | int temperature; | 88 | int temperature; |
@@ -132,6 +137,20 @@ static enum power_supply_property bq27x00_battery_props[] = { | |||
132 | POWER_SUPPLY_PROP_HEALTH, | 137 | POWER_SUPPLY_PROP_HEALTH, |
133 | }; | 138 | }; |
134 | 139 | ||
140 | static enum power_supply_property bq27425_battery_props[] = { | ||
141 | POWER_SUPPLY_PROP_STATUS, | ||
142 | POWER_SUPPLY_PROP_PRESENT, | ||
143 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
144 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
145 | POWER_SUPPLY_PROP_CAPACITY, | ||
146 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | ||
147 | POWER_SUPPLY_PROP_TEMP, | ||
148 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
149 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
150 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
151 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
152 | }; | ||
153 | |||
135 | static unsigned int poll_interval = 360; | 154 | static unsigned int poll_interval = 360; |
136 | module_param(poll_interval, uint, 0644); | 155 | module_param(poll_interval, uint, 0644); |
137 | MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ | 156 | MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ |
@@ -144,10 +163,24 @@ MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ | |||
144 | static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, | 163 | static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, |
145 | bool single) | 164 | bool single) |
146 | { | 165 | { |
166 | if (di->chip == BQ27425) | ||
167 | return di->bus.read(di, reg - BQ27425_REG_OFFSET, single); | ||
147 | return di->bus.read(di, reg, single); | 168 | return di->bus.read(di, reg, single); |
148 | } | 169 | } |
149 | 170 | ||
150 | /* | 171 | /* |
172 | * Higher versions of the chip like BQ27425 and BQ27500 | ||
173 | * differ from BQ27000 and BQ27200 in calculation of certain | ||
174 | * parameters. Hence we need to check for the chip type. | ||
175 | */ | ||
176 | static bool bq27xxx_is_chip_version_higher(struct bq27x00_device_info *di) | ||
177 | { | ||
178 | if (di->chip == BQ27425 || di->chip == BQ27500) | ||
179 | return true; | ||
180 | return false; | ||
181 | } | ||
182 | |||
183 | /* | ||
151 | * Return the battery Relative State-of-Charge | 184 | * Return the battery Relative State-of-Charge |
152 | * Or < 0 if something fails. | 185 | * Or < 0 if something fails. |
153 | */ | 186 | */ |
@@ -157,6 +190,8 @@ static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di) | |||
157 | 190 | ||
158 | if (di->chip == BQ27500) | 191 | if (di->chip == BQ27500) |
159 | rsoc = bq27x00_read(di, BQ27500_REG_SOC, false); | 192 | rsoc = bq27x00_read(di, BQ27500_REG_SOC, false); |
193 | else if (di->chip == BQ27425) | ||
194 | rsoc = bq27x00_read(di, BQ27425_REG_SOC, false); | ||
160 | else | 195 | else |
161 | rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true); | 196 | rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true); |
162 | 197 | ||
@@ -181,7 +216,7 @@ static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg) | |||
181 | return charge; | 216 | return charge; |
182 | } | 217 | } |
183 | 218 | ||
184 | if (di->chip == BQ27500) | 219 | if (bq27xxx_is_chip_version_higher(di)) |
185 | charge *= 1000; | 220 | charge *= 1000; |
186 | else | 221 | else |
187 | charge = charge * 3570 / BQ27000_RS; | 222 | charge = charge * 3570 / BQ27000_RS; |
@@ -215,7 +250,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) | |||
215 | { | 250 | { |
216 | int ilmd; | 251 | int ilmd; |
217 | 252 | ||
218 | if (di->chip == BQ27500) | 253 | if (bq27xxx_is_chip_version_higher(di)) |
219 | ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); | 254 | ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); |
220 | else | 255 | else |
221 | ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); | 256 | ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); |
@@ -225,7 +260,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) | |||
225 | return ilmd; | 260 | return ilmd; |
226 | } | 261 | } |
227 | 262 | ||
228 | if (di->chip == BQ27500) | 263 | if (bq27xxx_is_chip_version_higher(di)) |
229 | ilmd *= 1000; | 264 | ilmd *= 1000; |
230 | else | 265 | else |
231 | ilmd = ilmd * 256 * 3570 / BQ27000_RS; | 266 | ilmd = ilmd * 256 * 3570 / BQ27000_RS; |
@@ -269,7 +304,7 @@ static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di) | |||
269 | return temp; | 304 | return temp; |
270 | } | 305 | } |
271 | 306 | ||
272 | if (di->chip == BQ27500) | 307 | if (bq27xxx_is_chip_version_higher(di)) |
273 | temp -= 2731; | 308 | temp -= 2731; |
274 | else | 309 | else |
275 | temp = ((temp * 5) - 5463) / 2; | 310 | temp = ((temp * 5) - 5463) / 2; |
@@ -371,10 +406,12 @@ static void bq27x00_update(struct bq27x00_device_info *di) | |||
371 | { | 406 | { |
372 | struct bq27x00_reg_cache cache = {0, }; | 407 | struct bq27x00_reg_cache cache = {0, }; |
373 | bool is_bq27500 = di->chip == BQ27500; | 408 | bool is_bq27500 = di->chip == BQ27500; |
409 | bool is_bq27425 = di->chip == BQ27425; | ||
374 | 410 | ||
375 | cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500); | 411 | cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500); |
376 | if (cache.flags >= 0) { | 412 | if (cache.flags >= 0) { |
377 | if (!is_bq27500 && (cache.flags & BQ27000_FLAG_CI)) { | 413 | if (!is_bq27500 && !is_bq27425 |
414 | && (cache.flags & BQ27000_FLAG_CI)) { | ||
378 | dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n"); | 415 | dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n"); |
379 | cache.capacity = -ENODATA; | 416 | cache.capacity = -ENODATA; |
380 | cache.energy = -ENODATA; | 417 | cache.energy = -ENODATA; |
@@ -385,14 +422,24 @@ static void bq27x00_update(struct bq27x00_device_info *di) | |||
385 | cache.health = -ENODATA; | 422 | cache.health = -ENODATA; |
386 | } else { | 423 | } else { |
387 | cache.capacity = bq27x00_battery_read_rsoc(di); | 424 | cache.capacity = bq27x00_battery_read_rsoc(di); |
388 | cache.energy = bq27x00_battery_read_energy(di); | 425 | if (!is_bq27425) { |
389 | cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); | 426 | cache.energy = bq27x00_battery_read_energy(di); |
390 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); | 427 | cache.time_to_empty = |
391 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); | 428 | bq27x00_battery_read_time(di, |
429 | BQ27x00_REG_TTE); | ||
430 | cache.time_to_empty_avg = | ||
431 | bq27x00_battery_read_time(di, | ||
432 | BQ27x00_REG_TTECP); | ||
433 | cache.time_to_full = | ||
434 | bq27x00_battery_read_time(di, | ||
435 | BQ27x00_REG_TTF); | ||
436 | } | ||
392 | cache.charge_full = bq27x00_battery_read_lmd(di); | 437 | cache.charge_full = bq27x00_battery_read_lmd(di); |
393 | cache.health = bq27x00_battery_read_health(di); | 438 | cache.health = bq27x00_battery_read_health(di); |
394 | } | 439 | } |
395 | cache.temperature = bq27x00_battery_read_temperature(di); | 440 | cache.temperature = bq27x00_battery_read_temperature(di); |
441 | if (!is_bq27425) | ||
442 | cache.cycle_count = bq27x00_battery_read_cyct(di); | ||
396 | cache.cycle_count = bq27x00_battery_read_cyct(di); | 443 | cache.cycle_count = bq27x00_battery_read_cyct(di); |
397 | cache.power_avg = | 444 | cache.power_avg = |
398 | bq27x00_battery_read_pwr_avg(di, BQ27x00_POWER_AVG); | 445 | bq27x00_battery_read_pwr_avg(di, BQ27x00_POWER_AVG); |
@@ -441,7 +488,7 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di, | |||
441 | return curr; | 488 | return curr; |
442 | } | 489 | } |
443 | 490 | ||
444 | if (di->chip == BQ27500) { | 491 | if (bq27xxx_is_chip_version_higher(di)) { |
445 | /* bq27500 returns signed value */ | 492 | /* bq27500 returns signed value */ |
446 | val->intval = (int)((s16)curr) * 1000; | 493 | val->intval = (int)((s16)curr) * 1000; |
447 | } else { | 494 | } else { |
@@ -462,7 +509,7 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di, | |||
462 | { | 509 | { |
463 | int status; | 510 | int status; |
464 | 511 | ||
465 | if (di->chip == BQ27500) { | 512 | if (bq27xxx_is_chip_version_higher(di)) { |
466 | if (di->cache.flags & BQ27500_FLAG_FC) | 513 | if (di->cache.flags & BQ27500_FLAG_FC) |
467 | status = POWER_SUPPLY_STATUS_FULL; | 514 | status = POWER_SUPPLY_STATUS_FULL; |
468 | else if (di->cache.flags & BQ27500_FLAG_DSC) | 515 | else if (di->cache.flags & BQ27500_FLAG_DSC) |
@@ -490,7 +537,7 @@ static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di, | |||
490 | { | 537 | { |
491 | int level; | 538 | int level; |
492 | 539 | ||
493 | if (di->chip == BQ27500) { | 540 | if (bq27xxx_is_chip_version_higher(di)) { |
494 | if (di->cache.flags & BQ27500_FLAG_FC) | 541 | if (di->cache.flags & BQ27500_FLAG_FC) |
495 | level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; | 542 | level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; |
496 | else if (di->cache.flags & BQ27500_FLAG_SOC1) | 543 | else if (di->cache.flags & BQ27500_FLAG_SOC1) |
@@ -641,8 +688,14 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di) | |||
641 | int ret; | 688 | int ret; |
642 | 689 | ||
643 | di->bat.type = POWER_SUPPLY_TYPE_BATTERY; | 690 | di->bat.type = POWER_SUPPLY_TYPE_BATTERY; |
644 | di->bat.properties = bq27x00_battery_props; | 691 | di->chip = BQ27425; |
645 | di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); | 692 | if (di->chip == BQ27425) { |
693 | di->bat.properties = bq27425_battery_props; | ||
694 | di->bat.num_properties = ARRAY_SIZE(bq27425_battery_props); | ||
695 | } else { | ||
696 | di->bat.properties = bq27x00_battery_props; | ||
697 | di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); | ||
698 | } | ||
646 | di->bat.get_property = bq27x00_battery_get_property; | 699 | di->bat.get_property = bq27x00_battery_get_property; |
647 | di->bat.external_power_changed = bq27x00_external_power_changed; | 700 | di->bat.external_power_changed = bq27x00_external_power_changed; |
648 | 701 | ||
@@ -800,6 +853,7 @@ static int bq27x00_battery_remove(struct i2c_client *client) | |||
800 | static const struct i2c_device_id bq27x00_id[] = { | 853 | static const struct i2c_device_id bq27x00_id[] = { |
801 | { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */ | 854 | { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */ |
802 | { "bq27500", BQ27500 }, | 855 | { "bq27500", BQ27500 }, |
856 | { "bq27425", BQ27425 }, | ||
803 | {}, | 857 | {}, |
804 | }; | 858 | }; |
805 | MODULE_DEVICE_TABLE(i2c, bq27x00_id); | 859 | MODULE_DEVICE_TABLE(i2c, bq27x00_id); |