diff options
author | Pali Rohár <pali.rohar@gmail.com> | 2011-01-31 18:08:02 -0500 |
---|---|---|
committer | Lars-Peter Clausen <lars@metafoo.de> | 2011-02-22 05:02:44 -0500 |
commit | 631c17ee5daf0ca73688cb5e5216fc0e3e340483 (patch) | |
tree | 5e61bbbd7e2b62a0aa75ddfa8eca087528de7e7a /drivers/power | |
parent | 740b755a3b3433f5ee5f9ef54de5d1b4c08223cc (diff) |
bq27x00: Add new properties
This patch add support for reporting properties
POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_ENERGY_NOW in
module bq27x00_battery.
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Tested-by: Grazvydas Ignotas <notasas@gmail.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/bq27x00_battery.c | 152 |
1 files changed, 151 insertions, 1 deletions
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 25350fcbadb3..a1bd1ff753b3 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c | |||
@@ -16,6 +16,13 @@ | |||
16 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | 16 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | |||
20 | /* | ||
21 | * Datasheets: | ||
22 | * http://focus.ti.com/docs/prod/folders/print/bq27000.html | ||
23 | * http://focus.ti.com/docs/prod/folders/print/bq27500.html | ||
24 | */ | ||
25 | |||
19 | #include <linux/module.h> | 26 | #include <linux/module.h> |
20 | #include <linux/param.h> | 27 | #include <linux/param.h> |
21 | #include <linux/jiffies.h> | 28 | #include <linux/jiffies.h> |
@@ -30,7 +37,7 @@ | |||
30 | 37 | ||
31 | #include <linux/power/bq27x00_battery.h> | 38 | #include <linux/power/bq27x00_battery.h> |
32 | 39 | ||
33 | #define DRIVER_VERSION "1.1.0" | 40 | #define DRIVER_VERSION "1.2.0" |
34 | 41 | ||
35 | #define BQ27x00_REG_TEMP 0x06 | 42 | #define BQ27x00_REG_TEMP 0x06 |
36 | #define BQ27x00_REG_VOLT 0x08 | 43 | #define BQ27x00_REG_VOLT 0x08 |
@@ -39,11 +46,17 @@ | |||
39 | #define BQ27x00_REG_TTE 0x16 | 46 | #define BQ27x00_REG_TTE 0x16 |
40 | #define BQ27x00_REG_TTF 0x18 | 47 | #define BQ27x00_REG_TTF 0x18 |
41 | #define BQ27x00_REG_TTECP 0x26 | 48 | #define BQ27x00_REG_TTECP 0x26 |
49 | #define BQ27x00_REG_NAC 0x0C /* Nominal available capaciy */ | ||
50 | #define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ | ||
51 | #define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ | ||
52 | #define BQ27x00_REG_AE 0x22 /* Available enery */ | ||
42 | 53 | ||
43 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ | 54 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ |
55 | #define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ | ||
44 | #define BQ27000_FLAG_CHGS BIT(7) | 56 | #define BQ27000_FLAG_CHGS BIT(7) |
45 | 57 | ||
46 | #define BQ27500_REG_SOC 0x2c | 58 | #define BQ27500_REG_SOC 0x2c |
59 | #define BQ27500_REG_DCAP 0x3C /* Design capacity */ | ||
47 | #define BQ27500_FLAG_DSC BIT(0) | 60 | #define BQ27500_FLAG_DSC BIT(0) |
48 | #define BQ27500_FLAG_FC BIT(9) | 61 | #define BQ27500_FLAG_FC BIT(9) |
49 | 62 | ||
@@ -61,6 +74,8 @@ struct bq27x00_reg_cache { | |||
61 | int time_to_empty; | 74 | int time_to_empty; |
62 | int time_to_empty_avg; | 75 | int time_to_empty_avg; |
63 | int time_to_full; | 76 | int time_to_full; |
77 | int charge_full; | ||
78 | int charge_counter; | ||
64 | int capacity; | 79 | int capacity; |
65 | int flags; | 80 | int flags; |
66 | 81 | ||
@@ -73,6 +88,8 @@ struct bq27x00_device_info { | |||
73 | enum bq27x00_chip chip; | 88 | enum bq27x00_chip chip; |
74 | 89 | ||
75 | struct bq27x00_reg_cache cache; | 90 | struct bq27x00_reg_cache cache; |
91 | int charge_design_full; | ||
92 | |||
76 | unsigned long last_update; | 93 | unsigned long last_update; |
77 | struct delayed_work work; | 94 | struct delayed_work work; |
78 | 95 | ||
@@ -94,6 +111,11 @@ static enum power_supply_property bq27x00_battery_props[] = { | |||
94 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, | 111 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, |
95 | POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, | 112 | POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, |
96 | POWER_SUPPLY_PROP_TECHNOLOGY, | 113 | POWER_SUPPLY_PROP_TECHNOLOGY, |
114 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
115 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
116 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
117 | POWER_SUPPLY_PROP_CHARGE_COUNTER, | ||
118 | POWER_SUPPLY_PROP_ENERGY_NOW, | ||
97 | }; | 119 | }; |
98 | 120 | ||
99 | static unsigned int poll_interval = 360; | 121 | static unsigned int poll_interval = 360; |
@@ -131,6 +153,87 @@ static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di) | |||
131 | } | 153 | } |
132 | 154 | ||
133 | /* | 155 | /* |
156 | * Return a battery charge value in µAh | ||
157 | * Or < 0 if something fails. | ||
158 | */ | ||
159 | static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg) | ||
160 | { | ||
161 | int charge; | ||
162 | |||
163 | charge = bq27x00_read(di, reg, false); | ||
164 | if (charge < 0) { | ||
165 | dev_err(di->dev, "error reading nominal available capacity\n"); | ||
166 | return charge; | ||
167 | } | ||
168 | |||
169 | if (di->chip == BQ27500) | ||
170 | charge *= 1000; | ||
171 | else | ||
172 | charge = charge * 3570 / BQ27000_RS; | ||
173 | |||
174 | return charge; | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Return the battery Nominal available capaciy in µAh | ||
179 | * Or < 0 if something fails. | ||
180 | */ | ||
181 | static inline int bq27x00_battery_read_nac(struct bq27x00_device_info *di) | ||
182 | { | ||
183 | return bq27x00_battery_read_charge(di, BQ27x00_REG_NAC); | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Return the battery Last measured discharge in µAh | ||
188 | * Or < 0 if something fails. | ||
189 | */ | ||
190 | static inline int bq27x00_battery_read_lmd(struct bq27x00_device_info *di) | ||
191 | { | ||
192 | return bq27x00_battery_read_charge(di, BQ27x00_REG_LMD); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Return the battery Initial last measured discharge in µAh | ||
197 | * Or < 0 if something fails. | ||
198 | */ | ||
199 | static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) | ||
200 | { | ||
201 | int ilmd; | ||
202 | |||
203 | if (di->chip == BQ27500) | ||
204 | ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); | ||
205 | else | ||
206 | ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); | ||
207 | |||
208 | if (ilmd < 0) { | ||
209 | dev_err(di->dev, "error reading initial last measured discharge\n"); | ||
210 | return ilmd; | ||
211 | } | ||
212 | |||
213 | if (di->chip == BQ27500) | ||
214 | ilmd *= 1000; | ||
215 | else | ||
216 | ilmd = ilmd * 256 * 3570 / BQ27000_RS; | ||
217 | |||
218 | return ilmd; | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | * Return the battery Cycle count total | ||
223 | * Or < 0 if something fails. | ||
224 | */ | ||
225 | static int bq27x00_battery_read_cyct(struct bq27x00_device_info *di) | ||
226 | { | ||
227 | int cyct; | ||
228 | |||
229 | cyct = bq27x00_read(di, BQ27x00_REG_CYCT, false); | ||
230 | if (cyct < 0) | ||
231 | dev_err(di->dev, "error reading cycle count total\n"); | ||
232 | |||
233 | return cyct; | ||
234 | } | ||
235 | |||
236 | /* | ||
134 | * Read a time register. | 237 | * Read a time register. |
135 | * Return < 0 if something fails. | 238 | * Return < 0 if something fails. |
136 | */ | 239 | */ |
@@ -162,9 +265,15 @@ static void bq27x00_update(struct bq27x00_device_info *di) | |||
162 | cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); | 265 | cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); |
163 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); | 266 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); |
164 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); | 267 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); |
268 | cache.charge_full = bq27x00_battery_read_lmd(di); | ||
269 | cache.charge_counter = bq27x00_battery_read_cyct(di); | ||
165 | 270 | ||
166 | if (!is_bq27500) | 271 | if (!is_bq27500) |
167 | cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false); | 272 | cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false); |
273 | |||
274 | /* We only have to read charge design full once */ | ||
275 | if (di->charge_design_full <= 0) | ||
276 | di->charge_design_full = bq27x00_battery_read_ilmd(di); | ||
168 | } | 277 | } |
169 | 278 | ||
170 | /* Ignore current_now which is a snapshot of the current battery state | 279 | /* Ignore current_now which is a snapshot of the current battery state |
@@ -285,6 +394,32 @@ static int bq27x00_battery_voltage(struct bq27x00_device_info *di, | |||
285 | return 0; | 394 | return 0; |
286 | } | 395 | } |
287 | 396 | ||
397 | /* | ||
398 | * Return the battery Available energy in µWh | ||
399 | * Or < 0 if something fails. | ||
400 | */ | ||
401 | static int bq27x00_battery_energy(struct bq27x00_device_info *di, | ||
402 | union power_supply_propval *val) | ||
403 | { | ||
404 | int ae; | ||
405 | |||
406 | ae = bq27x00_read(di, BQ27x00_REG_AE, false); | ||
407 | if (ae < 0) { | ||
408 | dev_err(di->dev, "error reading available energy\n"); | ||
409 | return ae; | ||
410 | } | ||
411 | |||
412 | if (di->chip == BQ27500) | ||
413 | ae *= 1000; | ||
414 | else | ||
415 | ae = ae * 29200 / BQ27000_RS; | ||
416 | |||
417 | val->intval = ae; | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | |||
288 | static int bq27x00_simple_value(int value, | 423 | static int bq27x00_simple_value(int value, |
289 | union power_supply_propval *val) | 424 | union power_supply_propval *val) |
290 | { | 425 | { |
@@ -347,6 +482,21 @@ static int bq27x00_battery_get_property(struct power_supply *psy, | |||
347 | case POWER_SUPPLY_PROP_TECHNOLOGY: | 482 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
348 | val->intval = POWER_SUPPLY_TECHNOLOGY_LION; | 483 | val->intval = POWER_SUPPLY_TECHNOLOGY_LION; |
349 | break; | 484 | break; |
485 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
486 | ret = bq27x00_simple_value(bq27x00_battery_read_nac(di), val); | ||
487 | break; | ||
488 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
489 | ret = bq27x00_simple_value(di->cache.charge_full, val); | ||
490 | break; | ||
491 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
492 | ret = bq27x00_simple_value(di->charge_design_full, val); | ||
493 | break; | ||
494 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | ||
495 | ret = bq27x00_simple_value(di->cache.charge_counter, val); | ||
496 | break; | ||
497 | case POWER_SUPPLY_PROP_ENERGY_NOW: | ||
498 | ret = bq27x00_battery_energy(di, val); | ||
499 | break; | ||
350 | default: | 500 | default: |
351 | return -EINVAL; | 501 | return -EINVAL; |
352 | } | 502 | } |