diff options
author | Saranya Gopal <saranya.gopal@intel.com> | 2012-07-13 23:20:07 -0400 |
---|---|---|
committer | Anton Vorontsov <anton.vorontsov@linaro.org> | 2012-07-13 23:26:20 -0400 |
commit | a66f59ba2e994bf70274ef0513e24e0e7ae20c63 (patch) | |
tree | f21bd27fde5fbd681c70aec69ab9b5cc24d3e6af /drivers/power | |
parent | 45cd4fb28b43756afcd752ed1e8b3b836c1b1a2a (diff) |
bq27x00_battery: Add support for BQ27425 chip
This patch adds support for BQ27425 (TI) chip. This chip is same as
BQ27500 with few registers removed and register address map changed.
The data sheet for this chip is publicly available at
http://www.ti.com/product/bq27425-g1
Signed-off-by: Saranya Gopal <saranya.gopal@intel.com>
Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
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); |