diff options
-rw-r--r-- | drivers/power/bq20z75.c | 98 | ||||
-rw-r--r-- | include/linux/power_supply.h | 44 |
2 files changed, 131 insertions, 11 deletions
diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c index 492da27e1a47..4141775e5ff6 100644 --- a/drivers/power/bq20z75.c +++ b/drivers/power/bq20z75.c | |||
@@ -38,11 +38,22 @@ enum { | |||
38 | REG_CYCLE_COUNT, | 38 | REG_CYCLE_COUNT, |
39 | REG_SERIAL_NUMBER, | 39 | REG_SERIAL_NUMBER, |
40 | REG_REMAINING_CAPACITY, | 40 | REG_REMAINING_CAPACITY, |
41 | REG_REMAINING_CAPACITY_CHARGE, | ||
41 | REG_FULL_CHARGE_CAPACITY, | 42 | REG_FULL_CHARGE_CAPACITY, |
43 | REG_FULL_CHARGE_CAPACITY_CHARGE, | ||
42 | REG_DESIGN_CAPACITY, | 44 | REG_DESIGN_CAPACITY, |
45 | REG_DESIGN_CAPACITY_CHARGE, | ||
43 | REG_DESIGN_VOLTAGE, | 46 | REG_DESIGN_VOLTAGE, |
44 | }; | 47 | }; |
45 | 48 | ||
49 | /* Battery Mode defines */ | ||
50 | #define BATTERY_MODE_OFFSET 0x03 | ||
51 | #define BATTERY_MODE_MASK 0x8000 | ||
52 | enum bq20z75_battery_mode { | ||
53 | BATTERY_MODE_AMPS, | ||
54 | BATTERY_MODE_WATTS | ||
55 | }; | ||
56 | |||
46 | /* manufacturer access defines */ | 57 | /* manufacturer access defines */ |
47 | #define MANUFACTURER_ACCESS_STATUS 0x0006 | 58 | #define MANUFACTURER_ACCESS_STATUS 0x0006 |
48 | #define MANUFACTURER_ACCESS_SLEEP 0x0011 | 59 | #define MANUFACTURER_ACCESS_SLEEP 0x0011 |
@@ -78,8 +89,12 @@ static const struct bq20z75_device_data { | |||
78 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), | 89 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), |
79 | [REG_REMAINING_CAPACITY] = | 90 | [REG_REMAINING_CAPACITY] = |
80 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), | 91 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), |
92 | [REG_REMAINING_CAPACITY_CHARGE] = | ||
93 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535), | ||
81 | [REG_FULL_CHARGE_CAPACITY] = | 94 | [REG_FULL_CHARGE_CAPACITY] = |
82 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), | 95 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), |
96 | [REG_FULL_CHARGE_CAPACITY_CHARGE] = | ||
97 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535), | ||
83 | [REG_TIME_TO_EMPTY] = | 98 | [REG_TIME_TO_EMPTY] = |
84 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, | 99 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, |
85 | 65535), | 100 | 65535), |
@@ -93,6 +108,9 @@ static const struct bq20z75_device_data { | |||
93 | [REG_DESIGN_CAPACITY] = | 108 | [REG_DESIGN_CAPACITY] = |
94 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, | 109 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, |
95 | 65535), | 110 | 65535), |
111 | [REG_DESIGN_CAPACITY_CHARGE] = | ||
112 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0, | ||
113 | 65535), | ||
96 | [REG_DESIGN_VOLTAGE] = | 114 | [REG_DESIGN_VOLTAGE] = |
97 | BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, | 115 | BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, |
98 | 65535), | 116 | 65535), |
@@ -117,6 +135,9 @@ static enum power_supply_property bq20z75_properties[] = { | |||
117 | POWER_SUPPLY_PROP_ENERGY_NOW, | 135 | POWER_SUPPLY_PROP_ENERGY_NOW, |
118 | POWER_SUPPLY_PROP_ENERGY_FULL, | 136 | POWER_SUPPLY_PROP_ENERGY_FULL, |
119 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, | 137 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, |
138 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
139 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
140 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
120 | }; | 141 | }; |
121 | 142 | ||
122 | struct bq20z75_info { | 143 | struct bq20z75_info { |
@@ -260,6 +281,9 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, | |||
260 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | 281 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
261 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | 282 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: |
262 | case POWER_SUPPLY_PROP_CURRENT_NOW: | 283 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
284 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
285 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
286 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
263 | val->intval *= BASE_UNIT_CONVERSION; | 287 | val->intval *= BASE_UNIT_CONVERSION; |
264 | break; | 288 | break; |
265 | 289 | ||
@@ -281,11 +305,44 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, | |||
281 | } | 305 | } |
282 | } | 306 | } |
283 | 307 | ||
308 | static enum bq20z75_battery_mode | ||
309 | bq20z75_set_battery_mode(struct i2c_client *client, | ||
310 | enum bq20z75_battery_mode mode) | ||
311 | { | ||
312 | int ret, original_val; | ||
313 | |||
314 | original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET); | ||
315 | if (original_val < 0) | ||
316 | return original_val; | ||
317 | |||
318 | if ((original_val & BATTERY_MODE_MASK) == mode) | ||
319 | return mode; | ||
320 | |||
321 | if (mode == BATTERY_MODE_AMPS) | ||
322 | ret = original_val & ~BATTERY_MODE_MASK; | ||
323 | else | ||
324 | ret = original_val | BATTERY_MODE_MASK; | ||
325 | |||
326 | ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret); | ||
327 | if (ret < 0) | ||
328 | return ret; | ||
329 | |||
330 | return original_val & BATTERY_MODE_MASK; | ||
331 | } | ||
332 | |||
284 | static int bq20z75_get_battery_capacity(struct i2c_client *client, | 333 | static int bq20z75_get_battery_capacity(struct i2c_client *client, |
285 | int reg_offset, enum power_supply_property psp, | 334 | int reg_offset, enum power_supply_property psp, |
286 | union power_supply_propval *val) | 335 | union power_supply_propval *val) |
287 | { | 336 | { |
288 | s32 ret; | 337 | s32 ret; |
338 | enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS; | ||
339 | |||
340 | if (power_supply_is_amp_property(psp)) | ||
341 | mode = BATTERY_MODE_AMPS; | ||
342 | |||
343 | mode = bq20z75_set_battery_mode(client, mode); | ||
344 | if (mode < 0) | ||
345 | return mode; | ||
289 | 346 | ||
290 | ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); | 347 | ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); |
291 | if (ret < 0) | 348 | if (ret < 0) |
@@ -298,6 +355,10 @@ static int bq20z75_get_battery_capacity(struct i2c_client *client, | |||
298 | } else | 355 | } else |
299 | val->intval = ret; | 356 | val->intval = ret; |
300 | 357 | ||
358 | ret = bq20z75_set_battery_mode(client, mode); | ||
359 | if (ret < 0) | ||
360 | return ret; | ||
361 | |||
301 | return 0; | 362 | return 0; |
302 | } | 363 | } |
303 | 364 | ||
@@ -318,11 +379,25 @@ static int bq20z75_get_battery_serial_number(struct i2c_client *client, | |||
318 | return 0; | 379 | return 0; |
319 | } | 380 | } |
320 | 381 | ||
382 | static int bq20z75_get_property_index(struct i2c_client *client, | ||
383 | enum power_supply_property psp) | ||
384 | { | ||
385 | int count; | ||
386 | for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) | ||
387 | if (psp == bq20z75_data[count].psp) | ||
388 | return count; | ||
389 | |||
390 | dev_warn(&client->dev, | ||
391 | "%s: Invalid Property - %d\n", __func__, psp); | ||
392 | |||
393 | return -EINVAL; | ||
394 | } | ||
395 | |||
321 | static int bq20z75_get_property(struct power_supply *psy, | 396 | static int bq20z75_get_property(struct power_supply *psy, |
322 | enum power_supply_property psp, | 397 | enum power_supply_property psp, |
323 | union power_supply_propval *val) | 398 | union power_supply_propval *val) |
324 | { | 399 | { |
325 | int count; | 400 | int ps_index; |
326 | int ret; | 401 | int ret; |
327 | struct bq20z75_info *bq20z75_device = container_of(psy, | 402 | struct bq20z75_info *bq20z75_device = container_of(psy, |
328 | struct bq20z75_info, power_supply); | 403 | struct bq20z75_info, power_supply); |
@@ -343,13 +418,15 @@ static int bq20z75_get_property(struct power_supply *psy, | |||
343 | case POWER_SUPPLY_PROP_ENERGY_NOW: | 418 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
344 | case POWER_SUPPLY_PROP_ENERGY_FULL: | 419 | case POWER_SUPPLY_PROP_ENERGY_FULL: |
345 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | 420 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: |
421 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
422 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
423 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
346 | case POWER_SUPPLY_PROP_CAPACITY: | 424 | case POWER_SUPPLY_PROP_CAPACITY: |
347 | for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { | 425 | ps_index = bq20z75_get_property_index(client, psp); |
348 | if (psp == bq20z75_data[count].psp) | 426 | if (ps_index < 0) |
349 | break; | 427 | return ps_index; |
350 | } | ||
351 | 428 | ||
352 | ret = bq20z75_get_battery_capacity(client, count, psp, val); | 429 | ret = bq20z75_get_battery_capacity(client, ps_index, psp, val); |
353 | if (ret) | 430 | if (ret) |
354 | return ret; | 431 | return ret; |
355 | 432 | ||
@@ -369,12 +446,11 @@ static int bq20z75_get_property(struct power_supply *psy, | |||
369 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | 446 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
370 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: | 447 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: |
371 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | 448 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: |
372 | for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { | 449 | ps_index = bq20z75_get_property_index(client, psp); |
373 | if (psp == bq20z75_data[count].psp) | 450 | if (ps_index < 0) |
374 | break; | 451 | return ps_index; |
375 | } | ||
376 | 452 | ||
377 | ret = bq20z75_get_battery_property(client, count, psp, val); | 453 | ret = bq20z75_get_battery_property(client, ps_index, psp, val); |
378 | if (ret) | 454 | if (ret) |
379 | return ret; | 455 | return ret; |
380 | 456 | ||
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 7d7325685c42..e3419fc5541e 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h | |||
@@ -213,4 +213,48 @@ extern void power_supply_unregister(struct power_supply *psy); | |||
213 | /* For APM emulation, think legacy userspace. */ | 213 | /* For APM emulation, think legacy userspace. */ |
214 | extern struct class *power_supply_class; | 214 | extern struct class *power_supply_class; |
215 | 215 | ||
216 | static inline bool power_supply_is_amp_property(enum power_supply_property psp) | ||
217 | { | ||
218 | switch (psp) { | ||
219 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
220 | case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: | ||
221 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
222 | case POWER_SUPPLY_PROP_CHARGE_EMPTY: | ||
223 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
224 | case POWER_SUPPLY_PROP_CHARGE_AVG: | ||
225 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | ||
226 | case POWER_SUPPLY_PROP_CURRENT_MAX: | ||
227 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
228 | case POWER_SUPPLY_PROP_CURRENT_AVG: | ||
229 | return 1; | ||
230 | default: | ||
231 | break; | ||
232 | } | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static inline bool power_supply_is_watt_property(enum power_supply_property psp) | ||
238 | { | ||
239 | switch (psp) { | ||
240 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | ||
241 | case POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN: | ||
242 | case POWER_SUPPLY_PROP_ENERGY_FULL: | ||
243 | case POWER_SUPPLY_PROP_ENERGY_EMPTY: | ||
244 | case POWER_SUPPLY_PROP_ENERGY_NOW: | ||
245 | case POWER_SUPPLY_PROP_ENERGY_AVG: | ||
246 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | ||
247 | case POWER_SUPPLY_PROP_VOLTAGE_MIN: | ||
248 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | ||
249 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | ||
250 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
251 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | ||
252 | return 1; | ||
253 | default: | ||
254 | break; | ||
255 | } | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
216 | #endif /* __LINUX_POWER_SUPPLY_H__ */ | 260 | #endif /* __LINUX_POWER_SUPPLY_H__ */ |