Commit 56a9ccb7ba5ffd5f285e3a9628cb446192c8639c
Exists in
master
and in
39 other branches
Merge git://git.infradead.org/battery-2.6
* git://git.infradead.org/battery-2.6: (30 commits) bq20z75: Fix time and temp units bq20z75: Fix issues with present and suspend z2_battery: Fix count of properties s3c_adc_battery: Fix method names when PM not set z2_battery: Add MODULE_DEVICE_TABLE ds2782_battery: Add MODULE_DEVICE_TABLE bq20z75: Add MODULE_DEVICE_TABLE power_supply: Update power_supply_is_watt_property bq20z75: Add i2c retry mechanism bq20z75: Add optional battery detect gpio twl4030_charger: Make the driver atomic notifier safe bq27x00: Use single i2c_transfer call for property read bq27x00: Cleanup bq27x00_i2c_read bq27x00: Minor cleanups bq27x00: Give more specific reports on battery status bq27x00: Add MODULE_DEVICE_TABLE bq27x00: Add new properties bq27x00: Poll battery state bq27x00: Cache battery registers bq27x00: Add bq27000 support ...
Showing 15 changed files Side-by-side Diff
- drivers/leds/led-triggers.c
- drivers/power/Kconfig
- drivers/power/bq20z75.c
- drivers/power/bq27x00_battery.c
- drivers/power/ds2782_battery.c
- drivers/power/power_supply_core.c
- drivers/power/power_supply_leds.c
- drivers/power/power_supply_sysfs.c
- drivers/power/s3c_adc_battery.c
- drivers/power/twl4030_charger.c
- drivers/power/z2_battery.c
- include/linux/leds.h
- include/linux/power/bq20z75.h
- include/linux/power/bq27x00_battery.h
- include/linux/power_supply.h
drivers/leds/led-triggers.c
... | ... | @@ -231,6 +231,26 @@ |
231 | 231 | } |
232 | 232 | EXPORT_SYMBOL_GPL(led_trigger_event); |
233 | 233 | |
234 | +void led_trigger_blink(struct led_trigger *trigger, | |
235 | + unsigned long *delay_on, | |
236 | + unsigned long *delay_off) | |
237 | +{ | |
238 | + struct list_head *entry; | |
239 | + | |
240 | + if (!trigger) | |
241 | + return; | |
242 | + | |
243 | + read_lock(&trigger->leddev_list_lock); | |
244 | + list_for_each(entry, &trigger->led_cdevs) { | |
245 | + struct led_classdev *led_cdev; | |
246 | + | |
247 | + led_cdev = list_entry(entry, struct led_classdev, trig_list); | |
248 | + led_blink_set(led_cdev, delay_on, delay_off); | |
249 | + } | |
250 | + read_unlock(&trigger->leddev_list_lock); | |
251 | +} | |
252 | +EXPORT_SYMBOL_GPL(led_trigger_blink); | |
253 | + | |
234 | 254 | void led_trigger_register_simple(const char *name, struct led_trigger **tp) |
235 | 255 | { |
236 | 256 | struct led_trigger *trigger; |
drivers/power/Kconfig
... | ... | @@ -117,9 +117,23 @@ |
117 | 117 | |
118 | 118 | config BATTERY_BQ27x00 |
119 | 119 | tristate "BQ27x00 battery driver" |
120 | + help | |
121 | + Say Y here to enable support for batteries with BQ27x00 (I2C/HDQ) chips. | |
122 | + | |
123 | +config BATTERY_BQ27X00_I2C | |
124 | + bool "BQ27200/BQ27500 support" | |
125 | + depends on BATTERY_BQ27x00 | |
120 | 126 | depends on I2C |
127 | + default y | |
121 | 128 | help |
122 | 129 | Say Y here to enable support for batteries with BQ27x00 (I2C) chips. |
130 | + | |
131 | +config BATTERY_BQ27X00_PLATFORM | |
132 | + bool "BQ27000 support" | |
133 | + depends on BATTERY_BQ27x00 | |
134 | + default y | |
135 | + help | |
136 | + Say Y here to enable support for batteries with BQ27000 (HDQ) chips. | |
123 | 137 | |
124 | 138 | config BATTERY_DA9030 |
125 | 139 | tristate "DA9030 battery driver" |
drivers/power/bq20z75.c
... | ... | @@ -25,7 +25,11 @@ |
25 | 25 | #include <linux/power_supply.h> |
26 | 26 | #include <linux/i2c.h> |
27 | 27 | #include <linux/slab.h> |
28 | +#include <linux/interrupt.h> | |
29 | +#include <linux/gpio.h> | |
28 | 30 | |
31 | +#include <linux/power/bq20z75.h> | |
32 | + | |
29 | 33 | enum { |
30 | 34 | REG_MANUFACTURER_DATA, |
31 | 35 | REG_TEMPERATURE, |
32 | 36 | |
33 | 37 | |
34 | 38 | |
... | ... | @@ -38,11 +42,22 @@ |
38 | 42 | REG_CYCLE_COUNT, |
39 | 43 | REG_SERIAL_NUMBER, |
40 | 44 | REG_REMAINING_CAPACITY, |
45 | + REG_REMAINING_CAPACITY_CHARGE, | |
41 | 46 | REG_FULL_CHARGE_CAPACITY, |
47 | + REG_FULL_CHARGE_CAPACITY_CHARGE, | |
42 | 48 | REG_DESIGN_CAPACITY, |
49 | + REG_DESIGN_CAPACITY_CHARGE, | |
43 | 50 | REG_DESIGN_VOLTAGE, |
44 | 51 | }; |
45 | 52 | |
53 | +/* Battery Mode defines */ | |
54 | +#define BATTERY_MODE_OFFSET 0x03 | |
55 | +#define BATTERY_MODE_MASK 0x8000 | |
56 | +enum bq20z75_battery_mode { | |
57 | + BATTERY_MODE_AMPS, | |
58 | + BATTERY_MODE_WATTS | |
59 | +}; | |
60 | + | |
46 | 61 | /* manufacturer access defines */ |
47 | 62 | #define MANUFACTURER_ACCESS_STATUS 0x0006 |
48 | 63 | #define MANUFACTURER_ACCESS_SLEEP 0x0011 |
49 | 64 | |
... | ... | @@ -78,8 +93,12 @@ |
78 | 93 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), |
79 | 94 | [REG_REMAINING_CAPACITY] = |
80 | 95 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), |
96 | + [REG_REMAINING_CAPACITY_CHARGE] = | |
97 | + BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535), | |
81 | 98 | [REG_FULL_CHARGE_CAPACITY] = |
82 | 99 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), |
100 | + [REG_FULL_CHARGE_CAPACITY_CHARGE] = | |
101 | + BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535), | |
83 | 102 | [REG_TIME_TO_EMPTY] = |
84 | 103 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, |
85 | 104 | 65535), |
... | ... | @@ -93,6 +112,9 @@ |
93 | 112 | [REG_DESIGN_CAPACITY] = |
94 | 113 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, |
95 | 114 | 65535), |
115 | + [REG_DESIGN_CAPACITY_CHARGE] = | |
116 | + BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0, | |
117 | + 65535), | |
96 | 118 | [REG_DESIGN_VOLTAGE] = |
97 | 119 | BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, |
98 | 120 | 65535), |
99 | 121 | |
100 | 122 | |
101 | 123 | |
102 | 124 | |
103 | 125 | |
104 | 126 | |
105 | 127 | |
106 | 128 | |
107 | 129 | |
... | ... | @@ -117,39 +139,72 @@ |
117 | 139 | POWER_SUPPLY_PROP_ENERGY_NOW, |
118 | 140 | POWER_SUPPLY_PROP_ENERGY_FULL, |
119 | 141 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, |
142 | + POWER_SUPPLY_PROP_CHARGE_NOW, | |
143 | + POWER_SUPPLY_PROP_CHARGE_FULL, | |
144 | + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | |
120 | 145 | }; |
121 | 146 | |
122 | 147 | struct bq20z75_info { |
123 | - struct i2c_client *client; | |
124 | - struct power_supply power_supply; | |
148 | + struct i2c_client *client; | |
149 | + struct power_supply power_supply; | |
150 | + struct bq20z75_platform_data *pdata; | |
151 | + bool is_present; | |
152 | + bool gpio_detect; | |
153 | + bool enable_detection; | |
154 | + int irq; | |
125 | 155 | }; |
126 | 156 | |
127 | 157 | static int bq20z75_read_word_data(struct i2c_client *client, u8 address) |
128 | 158 | { |
129 | - s32 ret; | |
159 | + struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | |
160 | + s32 ret = 0; | |
161 | + int retries = 1; | |
130 | 162 | |
131 | - ret = i2c_smbus_read_word_data(client, address); | |
163 | + if (bq20z75_device->pdata) | |
164 | + retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1); | |
165 | + | |
166 | + while (retries > 0) { | |
167 | + ret = i2c_smbus_read_word_data(client, address); | |
168 | + if (ret >= 0) | |
169 | + break; | |
170 | + retries--; | |
171 | + } | |
172 | + | |
132 | 173 | if (ret < 0) { |
133 | - dev_err(&client->dev, | |
174 | + dev_dbg(&client->dev, | |
134 | 175 | "%s: i2c read at address 0x%x failed\n", |
135 | 176 | __func__, address); |
136 | 177 | return ret; |
137 | 178 | } |
179 | + | |
138 | 180 | return le16_to_cpu(ret); |
139 | 181 | } |
140 | 182 | |
141 | 183 | static int bq20z75_write_word_data(struct i2c_client *client, u8 address, |
142 | 184 | u16 value) |
143 | 185 | { |
144 | - s32 ret; | |
186 | + struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | |
187 | + s32 ret = 0; | |
188 | + int retries = 1; | |
145 | 189 | |
146 | - ret = i2c_smbus_write_word_data(client, address, le16_to_cpu(value)); | |
190 | + if (bq20z75_device->pdata) | |
191 | + retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1); | |
192 | + | |
193 | + while (retries > 0) { | |
194 | + ret = i2c_smbus_write_word_data(client, address, | |
195 | + le16_to_cpu(value)); | |
196 | + if (ret >= 0) | |
197 | + break; | |
198 | + retries--; | |
199 | + } | |
200 | + | |
147 | 201 | if (ret < 0) { |
148 | - dev_err(&client->dev, | |
202 | + dev_dbg(&client->dev, | |
149 | 203 | "%s: i2c write to address 0x%x failed\n", |
150 | 204 | __func__, address); |
151 | 205 | return ret; |
152 | 206 | } |
207 | + | |
153 | 208 | return 0; |
154 | 209 | } |
155 | 210 | |
156 | 211 | |
157 | 212 | |
158 | 213 | |
159 | 214 | |
... | ... | @@ -158,17 +213,32 @@ |
158 | 213 | union power_supply_propval *val) |
159 | 214 | { |
160 | 215 | s32 ret; |
216 | + struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | |
161 | 217 | |
218 | + if (psp == POWER_SUPPLY_PROP_PRESENT && | |
219 | + bq20z75_device->gpio_detect) { | |
220 | + ret = gpio_get_value( | |
221 | + bq20z75_device->pdata->battery_detect); | |
222 | + if (ret == bq20z75_device->pdata->battery_detect_present) | |
223 | + val->intval = 1; | |
224 | + else | |
225 | + val->intval = 0; | |
226 | + bq20z75_device->is_present = val->intval; | |
227 | + return ret; | |
228 | + } | |
229 | + | |
162 | 230 | /* Write to ManufacturerAccess with |
163 | 231 | * ManufacturerAccess command and then |
164 | 232 | * read the status */ |
165 | 233 | ret = bq20z75_write_word_data(client, |
166 | 234 | bq20z75_data[REG_MANUFACTURER_DATA].addr, |
167 | 235 | MANUFACTURER_ACCESS_STATUS); |
168 | - if (ret < 0) | |
236 | + if (ret < 0) { | |
237 | + if (psp == POWER_SUPPLY_PROP_PRESENT) | |
238 | + val->intval = 0; /* battery removed */ | |
169 | 239 | return ret; |
240 | + } | |
170 | 241 | |
171 | - | |
172 | 242 | ret = bq20z75_read_word_data(client, |
173 | 243 | bq20z75_data[REG_MANUFACTURER_DATA].addr); |
174 | 244 | if (ret < 0) |
175 | 245 | |
176 | 246 | |
177 | 247 | |
178 | 248 | |
... | ... | @@ -248,30 +318,39 @@ |
248 | 318 | { |
249 | 319 | #define BASE_UNIT_CONVERSION 1000 |
250 | 320 | #define BATTERY_MODE_CAP_MULT_WATT (10 * BASE_UNIT_CONVERSION) |
251 | -#define TIME_UNIT_CONVERSION 600 | |
252 | -#define TEMP_KELVIN_TO_CELCIUS 2731 | |
321 | +#define TIME_UNIT_CONVERSION 60 | |
322 | +#define TEMP_KELVIN_TO_CELSIUS 2731 | |
253 | 323 | switch (psp) { |
254 | 324 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
255 | 325 | case POWER_SUPPLY_PROP_ENERGY_FULL: |
256 | 326 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: |
327 | + /* bq20z75 provides energy in units of 10mWh. | |
328 | + * Convert to ยตWh | |
329 | + */ | |
257 | 330 | val->intval *= BATTERY_MODE_CAP_MULT_WATT; |
258 | 331 | break; |
259 | 332 | |
260 | 333 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
261 | 334 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: |
262 | 335 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
336 | + case POWER_SUPPLY_PROP_CHARGE_NOW: | |
337 | + case POWER_SUPPLY_PROP_CHARGE_FULL: | |
338 | + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | |
263 | 339 | val->intval *= BASE_UNIT_CONVERSION; |
264 | 340 | break; |
265 | 341 | |
266 | 342 | case POWER_SUPPLY_PROP_TEMP: |
267 | - /* bq20z75 provides battery tempreture in 0.1ยฐK | |
268 | - * so convert it to 0.1ยฐC */ | |
269 | - val->intval -= TEMP_KELVIN_TO_CELCIUS; | |
270 | - val->intval *= 10; | |
343 | + /* bq20z75 provides battery temperature in 0.1K | |
344 | + * so convert it to 0.1ยฐC | |
345 | + */ | |
346 | + val->intval -= TEMP_KELVIN_TO_CELSIUS; | |
271 | 347 | break; |
272 | 348 | |
273 | 349 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
274 | 350 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: |
351 | + /* bq20z75 provides time to empty and time to full in minutes. | |
352 | + * Convert to seconds | |
353 | + */ | |
275 | 354 | val->intval *= TIME_UNIT_CONVERSION; |
276 | 355 | break; |
277 | 356 | |
278 | 357 | |
279 | 358 | |
... | ... | @@ -281,12 +360,45 @@ |
281 | 360 | } |
282 | 361 | } |
283 | 362 | |
363 | +static enum bq20z75_battery_mode | |
364 | +bq20z75_set_battery_mode(struct i2c_client *client, | |
365 | + enum bq20z75_battery_mode mode) | |
366 | +{ | |
367 | + int ret, original_val; | |
368 | + | |
369 | + original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET); | |
370 | + if (original_val < 0) | |
371 | + return original_val; | |
372 | + | |
373 | + if ((original_val & BATTERY_MODE_MASK) == mode) | |
374 | + return mode; | |
375 | + | |
376 | + if (mode == BATTERY_MODE_AMPS) | |
377 | + ret = original_val & ~BATTERY_MODE_MASK; | |
378 | + else | |
379 | + ret = original_val | BATTERY_MODE_MASK; | |
380 | + | |
381 | + ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret); | |
382 | + if (ret < 0) | |
383 | + return ret; | |
384 | + | |
385 | + return original_val & BATTERY_MODE_MASK; | |
386 | +} | |
387 | + | |
284 | 388 | static int bq20z75_get_battery_capacity(struct i2c_client *client, |
285 | 389 | int reg_offset, enum power_supply_property psp, |
286 | 390 | union power_supply_propval *val) |
287 | 391 | { |
288 | 392 | s32 ret; |
393 | + enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS; | |
289 | 394 | |
395 | + if (power_supply_is_amp_property(psp)) | |
396 | + mode = BATTERY_MODE_AMPS; | |
397 | + | |
398 | + mode = bq20z75_set_battery_mode(client, mode); | |
399 | + if (mode < 0) | |
400 | + return mode; | |
401 | + | |
290 | 402 | ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); |
291 | 403 | if (ret < 0) |
292 | 404 | return ret; |
... | ... | @@ -298,6 +410,10 @@ |
298 | 410 | } else |
299 | 411 | val->intval = ret; |
300 | 412 | |
413 | + ret = bq20z75_set_battery_mode(client, mode); | |
414 | + if (ret < 0) | |
415 | + return ret; | |
416 | + | |
301 | 417 | return 0; |
302 | 418 | } |
303 | 419 | |
304 | 420 | |
... | ... | @@ -318,12 +434,25 @@ |
318 | 434 | return 0; |
319 | 435 | } |
320 | 436 | |
437 | +static int bq20z75_get_property_index(struct i2c_client *client, | |
438 | + enum power_supply_property psp) | |
439 | +{ | |
440 | + int count; | |
441 | + for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) | |
442 | + if (psp == bq20z75_data[count].psp) | |
443 | + return count; | |
444 | + | |
445 | + dev_warn(&client->dev, | |
446 | + "%s: Invalid Property - %d\n", __func__, psp); | |
447 | + | |
448 | + return -EINVAL; | |
449 | +} | |
450 | + | |
321 | 451 | static int bq20z75_get_property(struct power_supply *psy, |
322 | 452 | enum power_supply_property psp, |
323 | 453 | union power_supply_propval *val) |
324 | 454 | { |
325 | - int count; | |
326 | - int ret; | |
455 | + int ret = 0; | |
327 | 456 | struct bq20z75_info *bq20z75_device = container_of(psy, |
328 | 457 | struct bq20z75_info, power_supply); |
329 | 458 | struct i2c_client *client = bq20z75_device->client; |
... | ... | @@ -332,8 +461,8 @@ |
332 | 461 | case POWER_SUPPLY_PROP_PRESENT: |
333 | 462 | case POWER_SUPPLY_PROP_HEALTH: |
334 | 463 | ret = bq20z75_get_battery_presence_and_health(client, psp, val); |
335 | - if (ret) | |
336 | - return ret; | |
464 | + if (psp == POWER_SUPPLY_PROP_PRESENT) | |
465 | + return 0; | |
337 | 466 | break; |
338 | 467 | |
339 | 468 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
340 | 469 | |
341 | 470 | |
342 | 471 | |
... | ... | @@ -343,22 +472,19 @@ |
343 | 472 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
344 | 473 | case POWER_SUPPLY_PROP_ENERGY_FULL: |
345 | 474 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: |
475 | + case POWER_SUPPLY_PROP_CHARGE_NOW: | |
476 | + case POWER_SUPPLY_PROP_CHARGE_FULL: | |
477 | + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | |
346 | 478 | case POWER_SUPPLY_PROP_CAPACITY: |
347 | - for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { | |
348 | - if (psp == bq20z75_data[count].psp) | |
349 | - break; | |
350 | - } | |
479 | + ret = bq20z75_get_property_index(client, psp); | |
480 | + if (ret < 0) | |
481 | + break; | |
351 | 482 | |
352 | - ret = bq20z75_get_battery_capacity(client, count, psp, val); | |
353 | - if (ret) | |
354 | - return ret; | |
355 | - | |
483 | + ret = bq20z75_get_battery_capacity(client, ret, psp, val); | |
356 | 484 | break; |
357 | 485 | |
358 | 486 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: |
359 | 487 | ret = bq20z75_get_battery_serial_number(client, val); |
360 | - if (ret) | |
361 | - return ret; | |
362 | 488 | break; |
363 | 489 | |
364 | 490 | case POWER_SUPPLY_PROP_STATUS: |
365 | 491 | |
... | ... | @@ -369,15 +495,11 @@ |
369 | 495 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
370 | 496 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: |
371 | 497 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: |
372 | - for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { | |
373 | - if (psp == bq20z75_data[count].psp) | |
374 | - break; | |
375 | - } | |
498 | + ret = bq20z75_get_property_index(client, psp); | |
499 | + if (ret < 0) | |
500 | + break; | |
376 | 501 | |
377 | - ret = bq20z75_get_battery_property(client, count, psp, val); | |
378 | - if (ret) | |
379 | - return ret; | |
380 | - | |
502 | + ret = bq20z75_get_battery_property(client, ret, psp, val); | |
381 | 503 | break; |
382 | 504 | |
383 | 505 | default: |
384 | 506 | |
385 | 507 | |
386 | 508 | |
387 | 509 | |
388 | 510 | |
389 | 511 | |
390 | 512 | |
... | ... | @@ -386,26 +508,58 @@ |
386 | 508 | return -EINVAL; |
387 | 509 | } |
388 | 510 | |
389 | - /* Convert units to match requirements for power supply class */ | |
390 | - bq20z75_unit_adjustment(client, psp, val); | |
511 | + if (!bq20z75_device->enable_detection) | |
512 | + goto done; | |
391 | 513 | |
514 | + if (!bq20z75_device->gpio_detect && | |
515 | + bq20z75_device->is_present != (ret >= 0)) { | |
516 | + bq20z75_device->is_present = (ret >= 0); | |
517 | + power_supply_changed(&bq20z75_device->power_supply); | |
518 | + } | |
519 | + | |
520 | +done: | |
521 | + if (!ret) { | |
522 | + /* Convert units to match requirements for power supply class */ | |
523 | + bq20z75_unit_adjustment(client, psp, val); | |
524 | + } | |
525 | + | |
392 | 526 | dev_dbg(&client->dev, |
393 | - "%s: property = %d, value = %d\n", __func__, psp, val->intval); | |
527 | + "%s: property = %d, value = %x\n", __func__, psp, val->intval); | |
394 | 528 | |
529 | + if (ret && bq20z75_device->is_present) | |
530 | + return ret; | |
531 | + | |
532 | + /* battery not present, so return NODATA for properties */ | |
533 | + if (ret) | |
534 | + return -ENODATA; | |
535 | + | |
395 | 536 | return 0; |
396 | 537 | } |
397 | 538 | |
398 | -static int bq20z75_probe(struct i2c_client *client, | |
539 | +static irqreturn_t bq20z75_irq(int irq, void *devid) | |
540 | +{ | |
541 | + struct power_supply *battery = devid; | |
542 | + | |
543 | + power_supply_changed(battery); | |
544 | + | |
545 | + return IRQ_HANDLED; | |
546 | +} | |
547 | + | |
548 | +static int __devinit bq20z75_probe(struct i2c_client *client, | |
399 | 549 | const struct i2c_device_id *id) |
400 | 550 | { |
401 | 551 | struct bq20z75_info *bq20z75_device; |
552 | + struct bq20z75_platform_data *pdata = client->dev.platform_data; | |
402 | 553 | int rc; |
554 | + int irq; | |
403 | 555 | |
404 | 556 | bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL); |
405 | 557 | if (!bq20z75_device) |
406 | 558 | return -ENOMEM; |
407 | 559 | |
408 | 560 | bq20z75_device->client = client; |
561 | + bq20z75_device->enable_detection = false; | |
562 | + bq20z75_device->gpio_detect = false; | |
409 | 563 | bq20z75_device->power_supply.name = "battery"; |
410 | 564 | bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY; |
411 | 565 | bq20z75_device->power_supply.properties = bq20z75_properties; |
412 | 566 | |
413 | 567 | |
414 | 568 | |
415 | 569 | |
416 | 570 | |
... | ... | @@ -413,26 +567,86 @@ |
413 | 567 | ARRAY_SIZE(bq20z75_properties); |
414 | 568 | bq20z75_device->power_supply.get_property = bq20z75_get_property; |
415 | 569 | |
570 | + if (pdata) { | |
571 | + bq20z75_device->gpio_detect = | |
572 | + gpio_is_valid(pdata->battery_detect); | |
573 | + bq20z75_device->pdata = pdata; | |
574 | + } | |
575 | + | |
416 | 576 | i2c_set_clientdata(client, bq20z75_device); |
417 | 577 | |
578 | + if (!bq20z75_device->gpio_detect) | |
579 | + goto skip_gpio; | |
580 | + | |
581 | + rc = gpio_request(pdata->battery_detect, dev_name(&client->dev)); | |
582 | + if (rc) { | |
583 | + dev_warn(&client->dev, "Failed to request gpio: %d\n", rc); | |
584 | + bq20z75_device->gpio_detect = false; | |
585 | + goto skip_gpio; | |
586 | + } | |
587 | + | |
588 | + rc = gpio_direction_input(pdata->battery_detect); | |
589 | + if (rc) { | |
590 | + dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc); | |
591 | + gpio_free(pdata->battery_detect); | |
592 | + bq20z75_device->gpio_detect = false; | |
593 | + goto skip_gpio; | |
594 | + } | |
595 | + | |
596 | + irq = gpio_to_irq(pdata->battery_detect); | |
597 | + if (irq <= 0) { | |
598 | + dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); | |
599 | + gpio_free(pdata->battery_detect); | |
600 | + bq20z75_device->gpio_detect = false; | |
601 | + goto skip_gpio; | |
602 | + } | |
603 | + | |
604 | + rc = request_irq(irq, bq20z75_irq, | |
605 | + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | |
606 | + dev_name(&client->dev), &bq20z75_device->power_supply); | |
607 | + if (rc) { | |
608 | + dev_warn(&client->dev, "Failed to request irq: %d\n", rc); | |
609 | + gpio_free(pdata->battery_detect); | |
610 | + bq20z75_device->gpio_detect = false; | |
611 | + goto skip_gpio; | |
612 | + } | |
613 | + | |
614 | + bq20z75_device->irq = irq; | |
615 | + | |
616 | +skip_gpio: | |
617 | + | |
418 | 618 | rc = power_supply_register(&client->dev, &bq20z75_device->power_supply); |
419 | 619 | if (rc) { |
420 | 620 | dev_err(&client->dev, |
421 | 621 | "%s: Failed to register power supply\n", __func__); |
422 | - kfree(bq20z75_device); | |
423 | - return rc; | |
622 | + goto exit_psupply; | |
424 | 623 | } |
425 | 624 | |
426 | 625 | dev_info(&client->dev, |
427 | 626 | "%s: battery gas gauge device registered\n", client->name); |
428 | 627 | |
429 | 628 | return 0; |
629 | + | |
630 | +exit_psupply: | |
631 | + if (bq20z75_device->irq) | |
632 | + free_irq(bq20z75_device->irq, &bq20z75_device->power_supply); | |
633 | + if (bq20z75_device->gpio_detect) | |
634 | + gpio_free(pdata->battery_detect); | |
635 | + | |
636 | + kfree(bq20z75_device); | |
637 | + | |
638 | + return rc; | |
430 | 639 | } |
431 | 640 | |
432 | -static int bq20z75_remove(struct i2c_client *client) | |
641 | +static int __devexit bq20z75_remove(struct i2c_client *client) | |
433 | 642 | { |
434 | 643 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); |
435 | 644 | |
645 | + if (bq20z75_device->irq) | |
646 | + free_irq(bq20z75_device->irq, &bq20z75_device->power_supply); | |
647 | + if (bq20z75_device->gpio_detect) | |
648 | + gpio_free(bq20z75_device->pdata->battery_detect); | |
649 | + | |
436 | 650 | power_supply_unregister(&bq20z75_device->power_supply); |
437 | 651 | kfree(bq20z75_device); |
438 | 652 | bq20z75_device = NULL; |
439 | 653 | |
... | ... | @@ -444,13 +658,14 @@ |
444 | 658 | static int bq20z75_suspend(struct i2c_client *client, |
445 | 659 | pm_message_t state) |
446 | 660 | { |
661 | + struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | |
447 | 662 | s32 ret; |
448 | 663 | |
449 | 664 | /* write to manufacturer access with sleep command */ |
450 | 665 | ret = bq20z75_write_word_data(client, |
451 | 666 | bq20z75_data[REG_MANUFACTURER_DATA].addr, |
452 | 667 | MANUFACTURER_ACCESS_SLEEP); |
453 | - if (ret < 0) | |
668 | + if (bq20z75_device->is_present && ret < 0) | |
454 | 669 | return ret; |
455 | 670 | |
456 | 671 | return 0; |
457 | 672 | |
... | ... | @@ -465,10 +680,11 @@ |
465 | 680 | { "bq20z75", 0 }, |
466 | 681 | {} |
467 | 682 | }; |
683 | +MODULE_DEVICE_TABLE(i2c, bq20z75_id); | |
468 | 684 | |
469 | 685 | static struct i2c_driver bq20z75_battery_driver = { |
470 | 686 | .probe = bq20z75_probe, |
471 | - .remove = bq20z75_remove, | |
687 | + .remove = __devexit_p(bq20z75_remove), | |
472 | 688 | .suspend = bq20z75_suspend, |
473 | 689 | .resume = bq20z75_resume, |
474 | 690 | .id_table = bq20z75_id, |
drivers/power/bq27x00_battery.c
Changes suppressed. Click to show
... | ... | @@ -3,6 +3,7 @@ |
3 | 3 | * |
4 | 4 | * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it> |
5 | 5 | * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it> |
6 | + * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de> | |
6 | 7 | * |
7 | 8 | * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. |
8 | 9 | * |
... | ... | @@ -15,6 +16,13 @@ |
15 | 16 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
16 | 17 | * |
17 | 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 | + | |
18 | 26 | #include <linux/module.h> |
19 | 27 | #include <linux/param.h> |
20 | 28 | #include <linux/jiffies.h> |
21 | 29 | |
... | ... | @@ -27,8 +35,10 @@ |
27 | 35 | #include <linux/slab.h> |
28 | 36 | #include <asm/unaligned.h> |
29 | 37 | |
30 | -#define DRIVER_VERSION "1.1.0" | |
38 | +#include <linux/power/bq27x00_battery.h> | |
31 | 39 | |
40 | +#define DRIVER_VERSION "1.2.0" | |
41 | + | |
32 | 42 | #define BQ27x00_REG_TEMP 0x06 |
33 | 43 | #define BQ27x00_REG_VOLT 0x08 |
34 | 44 | #define BQ27x00_REG_AI 0x14 |
35 | 45 | |
36 | 46 | |
37 | 47 | |
38 | 48 | |
39 | 49 | |
40 | 50 | |
41 | 51 | |
42 | 52 | |
... | ... | @@ -36,36 +46,59 @@ |
36 | 46 | #define BQ27x00_REG_TTE 0x16 |
37 | 47 | #define BQ27x00_REG_TTF 0x18 |
38 | 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 */ | |
39 | 53 | |
40 | 54 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ |
55 | +#define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ | |
41 | 56 | #define BQ27000_FLAG_CHGS BIT(7) |
57 | +#define BQ27000_FLAG_FC BIT(5) | |
42 | 58 | |
43 | -#define BQ27500_REG_SOC 0x2c | |
59 | +#define BQ27500_REG_SOC 0x2C | |
60 | +#define BQ27500_REG_DCAP 0x3C /* Design capacity */ | |
44 | 61 | #define BQ27500_FLAG_DSC BIT(0) |
45 | 62 | #define BQ27500_FLAG_FC BIT(9) |
46 | 63 | |
47 | -/* If the system has several batteries we need a different name for each | |
48 | - * of them... | |
49 | - */ | |
50 | -static DEFINE_IDR(battery_id); | |
51 | -static DEFINE_MUTEX(battery_mutex); | |
64 | +#define BQ27000_RS 20 /* Resistor sense */ | |
52 | 65 | |
53 | 66 | struct bq27x00_device_info; |
54 | 67 | struct bq27x00_access_methods { |
55 | - int (*read)(u8 reg, int *rt_value, int b_single, | |
56 | - struct bq27x00_device_info *di); | |
68 | + int (*read)(struct bq27x00_device_info *di, u8 reg, bool single); | |
57 | 69 | }; |
58 | 70 | |
59 | 71 | enum bq27x00_chip { BQ27000, BQ27500 }; |
60 | 72 | |
73 | +struct bq27x00_reg_cache { | |
74 | + int temperature; | |
75 | + int time_to_empty; | |
76 | + int time_to_empty_avg; | |
77 | + int time_to_full; | |
78 | + int charge_full; | |
79 | + int charge_counter; | |
80 | + int capacity; | |
81 | + int flags; | |
82 | + | |
83 | + int current_now; | |
84 | +}; | |
85 | + | |
61 | 86 | struct bq27x00_device_info { |
62 | 87 | struct device *dev; |
63 | 88 | int id; |
64 | - struct bq27x00_access_methods *bus; | |
65 | - struct power_supply bat; | |
66 | 89 | enum bq27x00_chip chip; |
67 | 90 | |
68 | - struct i2c_client *client; | |
91 | + struct bq27x00_reg_cache cache; | |
92 | + int charge_design_full; | |
93 | + | |
94 | + unsigned long last_update; | |
95 | + struct delayed_work work; | |
96 | + | |
97 | + struct power_supply bat; | |
98 | + | |
99 | + struct bq27x00_access_methods bus; | |
100 | + | |
101 | + struct mutex lock; | |
69 | 102 | }; |
70 | 103 | |
71 | 104 | static enum power_supply_property bq27x00_battery_props[] = { |
72 | 105 | |
73 | 106 | |
74 | 107 | |
75 | 108 | |
76 | 109 | |
77 | 110 | |
78 | 111 | |
79 | 112 | |
80 | 113 | |
81 | 114 | |
82 | 115 | |
83 | 116 | |
84 | 117 | |
85 | 118 | |
86 | 119 | |
87 | 120 | |
88 | 121 | |
89 | 122 | |
90 | 123 | |
91 | 124 | |
92 | 125 | |
93 | 126 | |
94 | 127 | |
95 | 128 | |
96 | 129 | |
97 | 130 | |
98 | 131 | |
99 | 132 | |
100 | 133 | |
101 | 134 | |
102 | 135 | |
103 | 136 | |
104 | 137 | |
105 | 138 | |
106 | 139 | |
107 | 140 | |
108 | 141 | |
109 | 142 | |
110 | 143 | |
111 | 144 | |
112 | 145 | |
113 | 146 | |
114 | 147 | |
... | ... | @@ -78,167 +111,331 @@ |
78 | 111 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, |
79 | 112 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, |
80 | 113 | POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, |
114 | + POWER_SUPPLY_PROP_TECHNOLOGY, | |
115 | + POWER_SUPPLY_PROP_CHARGE_FULL, | |
116 | + POWER_SUPPLY_PROP_CHARGE_NOW, | |
117 | + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | |
118 | + POWER_SUPPLY_PROP_CHARGE_COUNTER, | |
119 | + POWER_SUPPLY_PROP_ENERGY_NOW, | |
81 | 120 | }; |
82 | 121 | |
122 | +static unsigned int poll_interval = 360; | |
123 | +module_param(poll_interval, uint, 0644); | |
124 | +MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ | |
125 | + "0 disables polling"); | |
126 | + | |
83 | 127 | /* |
84 | 128 | * Common code for BQ27x00 devices |
85 | 129 | */ |
86 | 130 | |
87 | -static int bq27x00_read(u8 reg, int *rt_value, int b_single, | |
88 | - struct bq27x00_device_info *di) | |
131 | +static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, | |
132 | + bool single) | |
89 | 133 | { |
90 | - return di->bus->read(reg, rt_value, b_single, di); | |
134 | + return di->bus.read(di, reg, single); | |
91 | 135 | } |
92 | 136 | |
93 | 137 | /* |
94 | - * Return the battery temperature in tenths of degree Celsius | |
138 | + * Return the battery Relative State-of-Charge | |
95 | 139 | * Or < 0 if something fails. |
96 | 140 | */ |
97 | -static int bq27x00_battery_temperature(struct bq27x00_device_info *di) | |
141 | +static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di) | |
98 | 142 | { |
99 | - int ret; | |
100 | - int temp = 0; | |
143 | + int rsoc; | |
101 | 144 | |
102 | - ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di); | |
103 | - if (ret) { | |
104 | - dev_err(di->dev, "error reading temperature\n"); | |
105 | - return ret; | |
145 | + if (di->chip == BQ27500) | |
146 | + rsoc = bq27x00_read(di, BQ27500_REG_SOC, false); | |
147 | + else | |
148 | + rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true); | |
149 | + | |
150 | + if (rsoc < 0) | |
151 | + dev_err(di->dev, "error reading relative State-of-Charge\n"); | |
152 | + | |
153 | + return rsoc; | |
154 | +} | |
155 | + | |
156 | +/* | |
157 | + * Return a battery charge value in ยตAh | |
158 | + * Or < 0 if something fails. | |
159 | + */ | |
160 | +static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg) | |
161 | +{ | |
162 | + int charge; | |
163 | + | |
164 | + charge = bq27x00_read(di, reg, false); | |
165 | + if (charge < 0) { | |
166 | + dev_err(di->dev, "error reading nominal available capacity\n"); | |
167 | + return charge; | |
106 | 168 | } |
107 | 169 | |
108 | 170 | if (di->chip == BQ27500) |
109 | - return temp - 2731; | |
171 | + charge *= 1000; | |
110 | 172 | else |
111 | - return ((temp >> 2) - 273) * 10; | |
173 | + charge = charge * 3570 / BQ27000_RS; | |
174 | + | |
175 | + return charge; | |
112 | 176 | } |
113 | 177 | |
114 | 178 | /* |
115 | - * Return the battery Voltage in milivolts | |
179 | + * Return the battery Nominal available capaciy in ยตAh | |
116 | 180 | * Or < 0 if something fails. |
117 | 181 | */ |
118 | -static int bq27x00_battery_voltage(struct bq27x00_device_info *di) | |
182 | +static inline int bq27x00_battery_read_nac(struct bq27x00_device_info *di) | |
119 | 183 | { |
120 | - int ret; | |
121 | - int volt = 0; | |
184 | + return bq27x00_battery_read_charge(di, BQ27x00_REG_NAC); | |
185 | +} | |
122 | 186 | |
123 | - ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di); | |
124 | - if (ret) { | |
125 | - dev_err(di->dev, "error reading voltage\n"); | |
126 | - return ret; | |
187 | +/* | |
188 | + * Return the battery Last measured discharge in ยตAh | |
189 | + * Or < 0 if something fails. | |
190 | + */ | |
191 | +static inline int bq27x00_battery_read_lmd(struct bq27x00_device_info *di) | |
192 | +{ | |
193 | + return bq27x00_battery_read_charge(di, BQ27x00_REG_LMD); | |
194 | +} | |
195 | + | |
196 | +/* | |
197 | + * Return the battery Initial last measured discharge in ยตAh | |
198 | + * Or < 0 if something fails. | |
199 | + */ | |
200 | +static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) | |
201 | +{ | |
202 | + int ilmd; | |
203 | + | |
204 | + if (di->chip == BQ27500) | |
205 | + ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); | |
206 | + else | |
207 | + ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); | |
208 | + | |
209 | + if (ilmd < 0) { | |
210 | + dev_err(di->dev, "error reading initial last measured discharge\n"); | |
211 | + return ilmd; | |
127 | 212 | } |
128 | 213 | |
129 | - return volt * 1000; | |
214 | + if (di->chip == BQ27500) | |
215 | + ilmd *= 1000; | |
216 | + else | |
217 | + ilmd = ilmd * 256 * 3570 / BQ27000_RS; | |
218 | + | |
219 | + return ilmd; | |
130 | 220 | } |
131 | 221 | |
132 | 222 | /* |
133 | - * Return the battery average current | |
134 | - * Note that current can be negative signed as well | |
135 | - * Or 0 if something fails. | |
223 | + * Return the battery Cycle count total | |
224 | + * Or < 0 if something fails. | |
136 | 225 | */ |
137 | -static int bq27x00_battery_current(struct bq27x00_device_info *di) | |
226 | +static int bq27x00_battery_read_cyct(struct bq27x00_device_info *di) | |
138 | 227 | { |
139 | - int ret; | |
140 | - int curr = 0; | |
141 | - int flags = 0; | |
228 | + int cyct; | |
142 | 229 | |
143 | - ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di); | |
144 | - if (ret) { | |
145 | - dev_err(di->dev, "error reading current\n"); | |
146 | - return 0; | |
230 | + cyct = bq27x00_read(di, BQ27x00_REG_CYCT, false); | |
231 | + if (cyct < 0) | |
232 | + dev_err(di->dev, "error reading cycle count total\n"); | |
233 | + | |
234 | + return cyct; | |
235 | +} | |
236 | + | |
237 | +/* | |
238 | + * Read a time register. | |
239 | + * Return < 0 if something fails. | |
240 | + */ | |
241 | +static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg) | |
242 | +{ | |
243 | + int tval; | |
244 | + | |
245 | + tval = bq27x00_read(di, reg, false); | |
246 | + if (tval < 0) { | |
247 | + dev_err(di->dev, "error reading register %02x: %d\n", reg, tval); | |
248 | + return tval; | |
147 | 249 | } |
148 | 250 | |
149 | - if (di->chip == BQ27500) { | |
150 | - /* bq27500 returns signed value */ | |
151 | - curr = (int)(s16)curr; | |
152 | - } else { | |
153 | - ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di); | |
154 | - if (ret < 0) { | |
155 | - dev_err(di->dev, "error reading flags\n"); | |
156 | - return 0; | |
157 | - } | |
158 | - if (flags & BQ27000_FLAG_CHGS) { | |
159 | - dev_dbg(di->dev, "negative current!\n"); | |
160 | - curr = -curr; | |
161 | - } | |
251 | + if (tval == 65535) | |
252 | + return -ENODATA; | |
253 | + | |
254 | + return tval * 60; | |
255 | +} | |
256 | + | |
257 | +static void bq27x00_update(struct bq27x00_device_info *di) | |
258 | +{ | |
259 | + struct bq27x00_reg_cache cache = {0, }; | |
260 | + bool is_bq27500 = di->chip == BQ27500; | |
261 | + | |
262 | + cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500); | |
263 | + if (cache.flags >= 0) { | |
264 | + cache.capacity = bq27x00_battery_read_rsoc(di); | |
265 | + cache.temperature = bq27x00_read(di, BQ27x00_REG_TEMP, false); | |
266 | + cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); | |
267 | + cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); | |
268 | + cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); | |
269 | + cache.charge_full = bq27x00_battery_read_lmd(di); | |
270 | + cache.charge_counter = bq27x00_battery_read_cyct(di); | |
271 | + | |
272 | + if (!is_bq27500) | |
273 | + cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false); | |
274 | + | |
275 | + /* We only have to read charge design full once */ | |
276 | + if (di->charge_design_full <= 0) | |
277 | + di->charge_design_full = bq27x00_battery_read_ilmd(di); | |
162 | 278 | } |
163 | 279 | |
164 | - return curr * 1000; | |
280 | + /* Ignore current_now which is a snapshot of the current battery state | |
281 | + * and is likely to be different even between two consecutive reads */ | |
282 | + if (memcmp(&di->cache, &cache, sizeof(cache) - sizeof(int)) != 0) { | |
283 | + di->cache = cache; | |
284 | + power_supply_changed(&di->bat); | |
285 | + } | |
286 | + | |
287 | + di->last_update = jiffies; | |
165 | 288 | } |
166 | 289 | |
290 | +static void bq27x00_battery_poll(struct work_struct *work) | |
291 | +{ | |
292 | + struct bq27x00_device_info *di = | |
293 | + container_of(work, struct bq27x00_device_info, work.work); | |
294 | + | |
295 | + bq27x00_update(di); | |
296 | + | |
297 | + if (poll_interval > 0) { | |
298 | + /* The timer does not have to be accurate. */ | |
299 | + set_timer_slack(&di->work.timer, poll_interval * HZ / 4); | |
300 | + schedule_delayed_work(&di->work, poll_interval * HZ); | |
301 | + } | |
302 | +} | |
303 | + | |
304 | + | |
167 | 305 | /* |
168 | - * Return the battery Relative State-of-Charge | |
306 | + * Return the battery temperature in tenths of degree Celsius | |
169 | 307 | * Or < 0 if something fails. |
170 | 308 | */ |
171 | -static int bq27x00_battery_rsoc(struct bq27x00_device_info *di) | |
309 | +static int bq27x00_battery_temperature(struct bq27x00_device_info *di, | |
310 | + union power_supply_propval *val) | |
172 | 311 | { |
173 | - int ret; | |
174 | - int rsoc = 0; | |
312 | + if (di->cache.temperature < 0) | |
313 | + return di->cache.temperature; | |
175 | 314 | |
176 | 315 | if (di->chip == BQ27500) |
177 | - ret = bq27x00_read(BQ27500_REG_SOC, &rsoc, 0, di); | |
316 | + val->intval = di->cache.temperature - 2731; | |
178 | 317 | else |
179 | - ret = bq27x00_read(BQ27000_REG_RSOC, &rsoc, 1, di); | |
180 | - if (ret) { | |
181 | - dev_err(di->dev, "error reading relative State-of-Charge\n"); | |
182 | - return ret; | |
318 | + val->intval = ((di->cache.temperature * 5) - 5463) / 2; | |
319 | + | |
320 | + return 0; | |
321 | +} | |
322 | + | |
323 | +/* | |
324 | + * Return the battery average current in ยตA | |
325 | + * Note that current can be negative signed as well | |
326 | + * Or 0 if something fails. | |
327 | + */ | |
328 | +static int bq27x00_battery_current(struct bq27x00_device_info *di, | |
329 | + union power_supply_propval *val) | |
330 | +{ | |
331 | + int curr; | |
332 | + | |
333 | + if (di->chip == BQ27500) | |
334 | + curr = bq27x00_read(di, BQ27x00_REG_AI, false); | |
335 | + else | |
336 | + curr = di->cache.current_now; | |
337 | + | |
338 | + if (curr < 0) | |
339 | + return curr; | |
340 | + | |
341 | + if (di->chip == BQ27500) { | |
342 | + /* bq27500 returns signed value */ | |
343 | + val->intval = (int)((s16)curr) * 1000; | |
344 | + } else { | |
345 | + if (di->cache.flags & BQ27000_FLAG_CHGS) { | |
346 | + dev_dbg(di->dev, "negative current!\n"); | |
347 | + curr = -curr; | |
348 | + } | |
349 | + | |
350 | + val->intval = curr * 3570 / BQ27000_RS; | |
183 | 351 | } |
184 | 352 | |
185 | - return rsoc; | |
353 | + return 0; | |
186 | 354 | } |
187 | 355 | |
188 | 356 | static int bq27x00_battery_status(struct bq27x00_device_info *di, |
189 | - union power_supply_propval *val) | |
357 | + union power_supply_propval *val) | |
190 | 358 | { |
191 | - int flags = 0; | |
192 | 359 | int status; |
193 | - int ret; | |
194 | 360 | |
195 | - ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di); | |
196 | - if (ret < 0) { | |
197 | - dev_err(di->dev, "error reading flags\n"); | |
198 | - return ret; | |
199 | - } | |
200 | - | |
201 | 361 | if (di->chip == BQ27500) { |
202 | - if (flags & BQ27500_FLAG_FC) | |
362 | + if (di->cache.flags & BQ27500_FLAG_FC) | |
203 | 363 | status = POWER_SUPPLY_STATUS_FULL; |
204 | - else if (flags & BQ27500_FLAG_DSC) | |
364 | + else if (di->cache.flags & BQ27500_FLAG_DSC) | |
205 | 365 | status = POWER_SUPPLY_STATUS_DISCHARGING; |
206 | 366 | else |
207 | 367 | status = POWER_SUPPLY_STATUS_CHARGING; |
208 | 368 | } else { |
209 | - if (flags & BQ27000_FLAG_CHGS) | |
369 | + if (di->cache.flags & BQ27000_FLAG_FC) | |
370 | + status = POWER_SUPPLY_STATUS_FULL; | |
371 | + else if (di->cache.flags & BQ27000_FLAG_CHGS) | |
210 | 372 | status = POWER_SUPPLY_STATUS_CHARGING; |
373 | + else if (power_supply_am_i_supplied(&di->bat)) | |
374 | + status = POWER_SUPPLY_STATUS_NOT_CHARGING; | |
211 | 375 | else |
212 | 376 | status = POWER_SUPPLY_STATUS_DISCHARGING; |
213 | 377 | } |
214 | 378 | |
215 | 379 | val->intval = status; |
380 | + | |
216 | 381 | return 0; |
217 | 382 | } |
218 | 383 | |
219 | 384 | /* |
220 | - * Read a time register. | |
221 | - * Return < 0 if something fails. | |
385 | + * Return the battery Voltage in milivolts | |
386 | + * Or < 0 if something fails. | |
222 | 387 | */ |
223 | -static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg, | |
224 | - union power_supply_propval *val) | |
388 | +static int bq27x00_battery_voltage(struct bq27x00_device_info *di, | |
389 | + union power_supply_propval *val) | |
225 | 390 | { |
226 | - int tval = 0; | |
227 | - int ret; | |
391 | + int volt; | |
228 | 392 | |
229 | - ret = bq27x00_read(reg, &tval, 0, di); | |
230 | - if (ret) { | |
231 | - dev_err(di->dev, "error reading register %02x\n", reg); | |
232 | - return ret; | |
393 | + volt = bq27x00_read(di, BQ27x00_REG_VOLT, false); | |
394 | + if (volt < 0) | |
395 | + return volt; | |
396 | + | |
397 | + val->intval = volt * 1000; | |
398 | + | |
399 | + return 0; | |
400 | +} | |
401 | + | |
402 | +/* | |
403 | + * Return the battery Available energy in ยตWh | |
404 | + * Or < 0 if something fails. | |
405 | + */ | |
406 | +static int bq27x00_battery_energy(struct bq27x00_device_info *di, | |
407 | + union power_supply_propval *val) | |
408 | +{ | |
409 | + int ae; | |
410 | + | |
411 | + ae = bq27x00_read(di, BQ27x00_REG_AE, false); | |
412 | + if (ae < 0) { | |
413 | + dev_err(di->dev, "error reading available energy\n"); | |
414 | + return ae; | |
233 | 415 | } |
234 | 416 | |
235 | - if (tval == 65535) | |
236 | - return -ENODATA; | |
417 | + if (di->chip == BQ27500) | |
418 | + ae *= 1000; | |
419 | + else | |
420 | + ae = ae * 29200 / BQ27000_RS; | |
237 | 421 | |
238 | - val->intval = tval * 60; | |
422 | + val->intval = ae; | |
423 | + | |
239 | 424 | return 0; |
240 | 425 | } |
241 | 426 | |
427 | + | |
428 | +static int bq27x00_simple_value(int value, | |
429 | + union power_supply_propval *val) | |
430 | +{ | |
431 | + if (value < 0) | |
432 | + return value; | |
433 | + | |
434 | + val->intval = value; | |
435 | + | |
436 | + return 0; | |
437 | +} | |
438 | + | |
242 | 439 | #define to_bq27x00_device_info(x) container_of((x), \ |
243 | 440 | struct bq27x00_device_info, bat); |
244 | 441 | |
245 | 442 | |
246 | 443 | |
247 | 444 | |
248 | 445 | |
249 | 446 | |
250 | 447 | |
251 | 448 | |
252 | 449 | |
253 | 450 | |
... | ... | @@ -249,34 +446,62 @@ |
249 | 446 | int ret = 0; |
250 | 447 | struct bq27x00_device_info *di = to_bq27x00_device_info(psy); |
251 | 448 | |
449 | + mutex_lock(&di->lock); | |
450 | + if (time_is_before_jiffies(di->last_update + 5 * HZ)) { | |
451 | + cancel_delayed_work_sync(&di->work); | |
452 | + bq27x00_battery_poll(&di->work.work); | |
453 | + } | |
454 | + mutex_unlock(&di->lock); | |
455 | + | |
456 | + if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) | |
457 | + return -ENODEV; | |
458 | + | |
252 | 459 | switch (psp) { |
253 | 460 | case POWER_SUPPLY_PROP_STATUS: |
254 | 461 | ret = bq27x00_battery_status(di, val); |
255 | 462 | break; |
256 | 463 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
464 | + ret = bq27x00_battery_voltage(di, val); | |
465 | + break; | |
257 | 466 | case POWER_SUPPLY_PROP_PRESENT: |
258 | - val->intval = bq27x00_battery_voltage(di); | |
259 | - if (psp == POWER_SUPPLY_PROP_PRESENT) | |
260 | - val->intval = val->intval <= 0 ? 0 : 1; | |
467 | + val->intval = di->cache.flags < 0 ? 0 : 1; | |
261 | 468 | break; |
262 | 469 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
263 | - val->intval = bq27x00_battery_current(di); | |
470 | + ret = bq27x00_battery_current(di, val); | |
264 | 471 | break; |
265 | 472 | case POWER_SUPPLY_PROP_CAPACITY: |
266 | - val->intval = bq27x00_battery_rsoc(di); | |
473 | + ret = bq27x00_simple_value(di->cache.capacity, val); | |
267 | 474 | break; |
268 | 475 | case POWER_SUPPLY_PROP_TEMP: |
269 | - val->intval = bq27x00_battery_temperature(di); | |
476 | + ret = bq27x00_battery_temperature(di, val); | |
270 | 477 | break; |
271 | 478 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: |
272 | - ret = bq27x00_battery_time(di, BQ27x00_REG_TTE, val); | |
479 | + ret = bq27x00_simple_value(di->cache.time_to_empty, val); | |
273 | 480 | break; |
274 | 481 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
275 | - ret = bq27x00_battery_time(di, BQ27x00_REG_TTECP, val); | |
482 | + ret = bq27x00_simple_value(di->cache.time_to_empty_avg, val); | |
276 | 483 | break; |
277 | 484 | case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: |
278 | - ret = bq27x00_battery_time(di, BQ27x00_REG_TTF, val); | |
485 | + ret = bq27x00_simple_value(di->cache.time_to_full, val); | |
279 | 486 | break; |
487 | + case POWER_SUPPLY_PROP_TECHNOLOGY: | |
488 | + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; | |
489 | + break; | |
490 | + case POWER_SUPPLY_PROP_CHARGE_NOW: | |
491 | + ret = bq27x00_simple_value(bq27x00_battery_read_nac(di), val); | |
492 | + break; | |
493 | + case POWER_SUPPLY_PROP_CHARGE_FULL: | |
494 | + ret = bq27x00_simple_value(di->cache.charge_full, val); | |
495 | + break; | |
496 | + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | |
497 | + ret = bq27x00_simple_value(di->charge_design_full, val); | |
498 | + break; | |
499 | + case POWER_SUPPLY_PROP_CHARGE_COUNTER: | |
500 | + ret = bq27x00_simple_value(di->cache.charge_counter, val); | |
501 | + break; | |
502 | + case POWER_SUPPLY_PROP_ENERGY_NOW: | |
503 | + ret = bq27x00_battery_energy(di, val); | |
504 | + break; | |
280 | 505 | default: |
281 | 506 | return -EINVAL; |
282 | 507 | } |
283 | 508 | |
284 | 509 | |
285 | 510 | |
286 | 511 | |
287 | 512 | |
288 | 513 | |
289 | 514 | |
290 | 515 | |
291 | 516 | |
292 | 517 | |
293 | 518 | |
... | ... | @@ -284,56 +509,91 @@ |
284 | 509 | return ret; |
285 | 510 | } |
286 | 511 | |
287 | -static void bq27x00_powersupply_init(struct bq27x00_device_info *di) | |
512 | +static void bq27x00_external_power_changed(struct power_supply *psy) | |
288 | 513 | { |
514 | + struct bq27x00_device_info *di = to_bq27x00_device_info(psy); | |
515 | + | |
516 | + cancel_delayed_work_sync(&di->work); | |
517 | + schedule_delayed_work(&di->work, 0); | |
518 | +} | |
519 | + | |
520 | +static int bq27x00_powersupply_init(struct bq27x00_device_info *di) | |
521 | +{ | |
522 | + int ret; | |
523 | + | |
289 | 524 | di->bat.type = POWER_SUPPLY_TYPE_BATTERY; |
290 | 525 | di->bat.properties = bq27x00_battery_props; |
291 | 526 | di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); |
292 | 527 | di->bat.get_property = bq27x00_battery_get_property; |
293 | - di->bat.external_power_changed = NULL; | |
528 | + di->bat.external_power_changed = bq27x00_external_power_changed; | |
529 | + | |
530 | + INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll); | |
531 | + mutex_init(&di->lock); | |
532 | + | |
533 | + ret = power_supply_register(di->dev, &di->bat); | |
534 | + if (ret) { | |
535 | + dev_err(di->dev, "failed to register battery: %d\n", ret); | |
536 | + return ret; | |
537 | + } | |
538 | + | |
539 | + dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION); | |
540 | + | |
541 | + bq27x00_update(di); | |
542 | + | |
543 | + return 0; | |
294 | 544 | } |
295 | 545 | |
296 | -/* | |
297 | - * i2c specific code | |
546 | +static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di) | |
547 | +{ | |
548 | + cancel_delayed_work_sync(&di->work); | |
549 | + | |
550 | + power_supply_unregister(&di->bat); | |
551 | + | |
552 | + mutex_destroy(&di->lock); | |
553 | +} | |
554 | + | |
555 | + | |
556 | +/* i2c specific code */ | |
557 | +#ifdef CONFIG_BATTERY_BQ27X00_I2C | |
558 | + | |
559 | +/* If the system has several batteries we need a different name for each | |
560 | + * of them... | |
298 | 561 | */ |
562 | +static DEFINE_IDR(battery_id); | |
563 | +static DEFINE_MUTEX(battery_mutex); | |
299 | 564 | |
300 | -static int bq27x00_read_i2c(u8 reg, int *rt_value, int b_single, | |
301 | - struct bq27x00_device_info *di) | |
565 | +static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, bool single) | |
302 | 566 | { |
303 | - struct i2c_client *client = di->client; | |
304 | - struct i2c_msg msg[1]; | |
567 | + struct i2c_client *client = to_i2c_client(di->dev); | |
568 | + struct i2c_msg msg[2]; | |
305 | 569 | unsigned char data[2]; |
306 | - int err; | |
570 | + int ret; | |
307 | 571 | |
308 | 572 | if (!client->adapter) |
309 | 573 | return -ENODEV; |
310 | 574 | |
311 | - msg->addr = client->addr; | |
312 | - msg->flags = 0; | |
313 | - msg->len = 1; | |
314 | - msg->buf = data; | |
575 | + msg[0].addr = client->addr; | |
576 | + msg[0].flags = 0; | |
577 | + msg[0].buf = ® | |
578 | + msg[0].len = sizeof(reg); | |
579 | + msg[1].addr = client->addr; | |
580 | + msg[1].flags = I2C_M_RD; | |
581 | + msg[1].buf = data; | |
582 | + if (single) | |
583 | + msg[1].len = 1; | |
584 | + else | |
585 | + msg[1].len = 2; | |
315 | 586 | |
316 | - data[0] = reg; | |
317 | - err = i2c_transfer(client->adapter, msg, 1); | |
587 | + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); | |
588 | + if (ret < 0) | |
589 | + return ret; | |
318 | 590 | |
319 | - if (err >= 0) { | |
320 | - if (!b_single) | |
321 | - msg->len = 2; | |
322 | - else | |
323 | - msg->len = 1; | |
591 | + if (!single) | |
592 | + ret = get_unaligned_le16(data); | |
593 | + else | |
594 | + ret = data[0]; | |
324 | 595 | |
325 | - msg->flags = I2C_M_RD; | |
326 | - err = i2c_transfer(client->adapter, msg, 1); | |
327 | - if (err >= 0) { | |
328 | - if (!b_single) | |
329 | - *rt_value = get_unaligned_le16(data); | |
330 | - else | |
331 | - *rt_value = data[0]; | |
332 | - | |
333 | - return 0; | |
334 | - } | |
335 | - } | |
336 | - return err; | |
596 | + return ret; | |
337 | 597 | } |
338 | 598 | |
339 | 599 | static int bq27x00_battery_probe(struct i2c_client *client, |
... | ... | @@ -341,7 +601,6 @@ |
341 | 601 | { |
342 | 602 | char *name; |
343 | 603 | struct bq27x00_device_info *di; |
344 | - struct bq27x00_access_methods *bus; | |
345 | 604 | int num; |
346 | 605 | int retval = 0; |
347 | 606 | |
348 | 607 | |
349 | 608 | |
350 | 609 | |
351 | 610 | |
352 | 611 | |
353 | 612 | |
354 | 613 | |
... | ... | @@ -368,38 +627,20 @@ |
368 | 627 | retval = -ENOMEM; |
369 | 628 | goto batt_failed_2; |
370 | 629 | } |
630 | + | |
371 | 631 | di->id = num; |
632 | + di->dev = &client->dev; | |
372 | 633 | di->chip = id->driver_data; |
634 | + di->bat.name = name; | |
635 | + di->bus.read = &bq27x00_read_i2c; | |
373 | 636 | |
374 | - bus = kzalloc(sizeof(*bus), GFP_KERNEL); | |
375 | - if (!bus) { | |
376 | - dev_err(&client->dev, "failed to allocate access method " | |
377 | - "data\n"); | |
378 | - retval = -ENOMEM; | |
637 | + if (bq27x00_powersupply_init(di)) | |
379 | 638 | goto batt_failed_3; |
380 | - } | |
381 | 639 | |
382 | 640 | i2c_set_clientdata(client, di); |
383 | - di->dev = &client->dev; | |
384 | - di->bat.name = name; | |
385 | - bus->read = &bq27x00_read_i2c; | |
386 | - di->bus = bus; | |
387 | - di->client = client; | |
388 | 641 | |
389 | - bq27x00_powersupply_init(di); | |
390 | - | |
391 | - retval = power_supply_register(&client->dev, &di->bat); | |
392 | - if (retval) { | |
393 | - dev_err(&client->dev, "failed to register battery\n"); | |
394 | - goto batt_failed_4; | |
395 | - } | |
396 | - | |
397 | - dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION); | |
398 | - | |
399 | 642 | return 0; |
400 | 643 | |
401 | -batt_failed_4: | |
402 | - kfree(bus); | |
403 | 644 | batt_failed_3: |
404 | 645 | kfree(di); |
405 | 646 | batt_failed_2: |
406 | 647 | |
... | ... | @@ -416,9 +657,8 @@ |
416 | 657 | { |
417 | 658 | struct bq27x00_device_info *di = i2c_get_clientdata(client); |
418 | 659 | |
419 | - power_supply_unregister(&di->bat); | |
660 | + bq27x00_powersupply_unregister(di); | |
420 | 661 | |
421 | - kfree(di->bus); | |
422 | 662 | kfree(di->bat.name); |
423 | 663 | |
424 | 664 | mutex_lock(&battery_mutex); |
425 | 665 | |
... | ... | @@ -430,15 +670,12 @@ |
430 | 670 | return 0; |
431 | 671 | } |
432 | 672 | |
433 | -/* | |
434 | - * Module stuff | |
435 | - */ | |
436 | - | |
437 | 673 | static const struct i2c_device_id bq27x00_id[] = { |
438 | 674 | { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */ |
439 | 675 | { "bq27500", BQ27500 }, |
440 | 676 | {}, |
441 | 677 | }; |
678 | +MODULE_DEVICE_TABLE(i2c, bq27x00_id); | |
442 | 679 | |
443 | 680 | static struct i2c_driver bq27x00_battery_driver = { |
444 | 681 | .driver = { |
445 | 682 | |
446 | 683 | |
447 | 684 | |
448 | 685 | |
... | ... | @@ -449,21 +686,173 @@ |
449 | 686 | .id_table = bq27x00_id, |
450 | 687 | }; |
451 | 688 | |
689 | +static inline int bq27x00_battery_i2c_init(void) | |
690 | +{ | |
691 | + int ret = i2c_add_driver(&bq27x00_battery_driver); | |
692 | + if (ret) | |
693 | + printk(KERN_ERR "Unable to register BQ27x00 i2c driver\n"); | |
694 | + | |
695 | + return ret; | |
696 | +} | |
697 | + | |
698 | +static inline void bq27x00_battery_i2c_exit(void) | |
699 | +{ | |
700 | + i2c_del_driver(&bq27x00_battery_driver); | |
701 | +} | |
702 | + | |
703 | +#else | |
704 | + | |
705 | +static inline int bq27x00_battery_i2c_init(void) { return 0; } | |
706 | +static inline void bq27x00_battery_i2c_exit(void) {}; | |
707 | + | |
708 | +#endif | |
709 | + | |
710 | +/* platform specific code */ | |
711 | +#ifdef CONFIG_BATTERY_BQ27X00_PLATFORM | |
712 | + | |
713 | +static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg, | |
714 | + bool single) | |
715 | +{ | |
716 | + struct device *dev = di->dev; | |
717 | + struct bq27000_platform_data *pdata = dev->platform_data; | |
718 | + unsigned int timeout = 3; | |
719 | + int upper, lower; | |
720 | + int temp; | |
721 | + | |
722 | + if (!single) { | |
723 | + /* Make sure the value has not changed in between reading the | |
724 | + * lower and the upper part */ | |
725 | + upper = pdata->read(dev, reg + 1); | |
726 | + do { | |
727 | + temp = upper; | |
728 | + if (upper < 0) | |
729 | + return upper; | |
730 | + | |
731 | + lower = pdata->read(dev, reg); | |
732 | + if (lower < 0) | |
733 | + return lower; | |
734 | + | |
735 | + upper = pdata->read(dev, reg + 1); | |
736 | + } while (temp != upper && --timeout); | |
737 | + | |
738 | + if (timeout == 0) | |
739 | + return -EIO; | |
740 | + | |
741 | + return (upper << 8) | lower; | |
742 | + } | |
743 | + | |
744 | + return pdata->read(dev, reg); | |
745 | +} | |
746 | + | |
747 | +static int __devinit bq27000_battery_probe(struct platform_device *pdev) | |
748 | +{ | |
749 | + struct bq27x00_device_info *di; | |
750 | + struct bq27000_platform_data *pdata = pdev->dev.platform_data; | |
751 | + int ret; | |
752 | + | |
753 | + if (!pdata) { | |
754 | + dev_err(&pdev->dev, "no platform_data supplied\n"); | |
755 | + return -EINVAL; | |
756 | + } | |
757 | + | |
758 | + if (!pdata->read) { | |
759 | + dev_err(&pdev->dev, "no hdq read callback supplied\n"); | |
760 | + return -EINVAL; | |
761 | + } | |
762 | + | |
763 | + di = kzalloc(sizeof(*di), GFP_KERNEL); | |
764 | + if (!di) { | |
765 | + dev_err(&pdev->dev, "failed to allocate device info data\n"); | |
766 | + return -ENOMEM; | |
767 | + } | |
768 | + | |
769 | + platform_set_drvdata(pdev, di); | |
770 | + | |
771 | + di->dev = &pdev->dev; | |
772 | + di->chip = BQ27000; | |
773 | + | |
774 | + di->bat.name = pdata->name ?: dev_name(&pdev->dev); | |
775 | + di->bus.read = &bq27000_read_platform; | |
776 | + | |
777 | + ret = bq27x00_powersupply_init(di); | |
778 | + if (ret) | |
779 | + goto err_free; | |
780 | + | |
781 | + return 0; | |
782 | + | |
783 | +err_free: | |
784 | + platform_set_drvdata(pdev, NULL); | |
785 | + kfree(di); | |
786 | + | |
787 | + return ret; | |
788 | +} | |
789 | + | |
790 | +static int __devexit bq27000_battery_remove(struct platform_device *pdev) | |
791 | +{ | |
792 | + struct bq27x00_device_info *di = platform_get_drvdata(pdev); | |
793 | + | |
794 | + bq27x00_powersupply_unregister(di); | |
795 | + | |
796 | + platform_set_drvdata(pdev, NULL); | |
797 | + kfree(di); | |
798 | + | |
799 | + return 0; | |
800 | +} | |
801 | + | |
802 | +static struct platform_driver bq27000_battery_driver = { | |
803 | + .probe = bq27000_battery_probe, | |
804 | + .remove = __devexit_p(bq27000_battery_remove), | |
805 | + .driver = { | |
806 | + .name = "bq27000-battery", | |
807 | + .owner = THIS_MODULE, | |
808 | + }, | |
809 | +}; | |
810 | + | |
811 | +static inline int bq27x00_battery_platform_init(void) | |
812 | +{ | |
813 | + int ret = platform_driver_register(&bq27000_battery_driver); | |
814 | + if (ret) | |
815 | + printk(KERN_ERR "Unable to register BQ27000 platform driver\n"); | |
816 | + | |
817 | + return ret; | |
818 | +} | |
819 | + | |
820 | +static inline void bq27x00_battery_platform_exit(void) | |
821 | +{ | |
822 | + platform_driver_unregister(&bq27000_battery_driver); | |
823 | +} | |
824 | + | |
825 | +#else | |
826 | + | |
827 | +static inline int bq27x00_battery_platform_init(void) { return 0; } | |
828 | +static inline void bq27x00_battery_platform_exit(void) {}; | |
829 | + | |
830 | +#endif | |
831 | + | |
832 | +/* | |
833 | + * Module stuff | |
834 | + */ | |
835 | + | |
452 | 836 | static int __init bq27x00_battery_init(void) |
453 | 837 | { |
454 | 838 | int ret; |
455 | 839 | |
456 | - ret = i2c_add_driver(&bq27x00_battery_driver); | |
840 | + ret = bq27x00_battery_i2c_init(); | |
457 | 841 | if (ret) |
458 | - printk(KERN_ERR "Unable to register BQ27x00 driver\n"); | |
842 | + return ret; | |
459 | 843 | |
844 | + ret = bq27x00_battery_platform_init(); | |
845 | + if (ret) | |
846 | + bq27x00_battery_i2c_exit(); | |
847 | + | |
460 | 848 | return ret; |
461 | 849 | } |
462 | 850 | module_init(bq27x00_battery_init); |
463 | 851 | |
464 | 852 | static void __exit bq27x00_battery_exit(void) |
465 | 853 | { |
466 | - i2c_del_driver(&bq27x00_battery_driver); | |
854 | + bq27x00_battery_platform_exit(); | |
855 | + bq27x00_battery_i2c_exit(); | |
467 | 856 | } |
468 | 857 | module_exit(bq27x00_battery_exit); |
469 | 858 |
drivers/power/ds2782_battery.c
drivers/power/power_supply_core.c
... | ... | @@ -171,6 +171,8 @@ |
171 | 171 | dev_set_drvdata(dev, psy); |
172 | 172 | psy->dev = dev; |
173 | 173 | |
174 | + INIT_WORK(&psy->changed_work, power_supply_changed_work); | |
175 | + | |
174 | 176 | rc = kobject_set_name(&dev->kobj, "%s", psy->name); |
175 | 177 | if (rc) |
176 | 178 | goto kobject_set_name_failed; |
... | ... | @@ -178,8 +180,6 @@ |
178 | 180 | rc = device_add(dev); |
179 | 181 | if (rc) |
180 | 182 | goto device_add_failed; |
181 | - | |
182 | - INIT_WORK(&psy->changed_work, power_supply_changed_work); | |
183 | 183 | |
184 | 184 | rc = power_supply_create_triggers(psy); |
185 | 185 | if (rc) |
drivers/power/power_supply_leds.c
... | ... | @@ -21,6 +21,8 @@ |
21 | 21 | static void power_supply_update_bat_leds(struct power_supply *psy) |
22 | 22 | { |
23 | 23 | union power_supply_propval status; |
24 | + unsigned long delay_on = 0; | |
25 | + unsigned long delay_off = 0; | |
24 | 26 | |
25 | 27 | if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) |
26 | 28 | return; |
27 | 29 | |
28 | 30 | |
... | ... | @@ -32,16 +34,22 @@ |
32 | 34 | led_trigger_event(psy->charging_full_trig, LED_FULL); |
33 | 35 | led_trigger_event(psy->charging_trig, LED_OFF); |
34 | 36 | led_trigger_event(psy->full_trig, LED_FULL); |
37 | + led_trigger_event(psy->charging_blink_full_solid_trig, | |
38 | + LED_FULL); | |
35 | 39 | break; |
36 | 40 | case POWER_SUPPLY_STATUS_CHARGING: |
37 | 41 | led_trigger_event(psy->charging_full_trig, LED_FULL); |
38 | 42 | led_trigger_event(psy->charging_trig, LED_FULL); |
39 | 43 | led_trigger_event(psy->full_trig, LED_OFF); |
44 | + led_trigger_blink(psy->charging_blink_full_solid_trig, | |
45 | + &delay_on, &delay_off); | |
40 | 46 | break; |
41 | 47 | default: |
42 | 48 | led_trigger_event(psy->charging_full_trig, LED_OFF); |
43 | 49 | led_trigger_event(psy->charging_trig, LED_OFF); |
44 | 50 | led_trigger_event(psy->full_trig, LED_OFF); |
51 | + led_trigger_event(psy->charging_blink_full_solid_trig, | |
52 | + LED_OFF); | |
45 | 53 | break; |
46 | 54 | } |
47 | 55 | } |
48 | 56 | |
49 | 57 | |
... | ... | @@ -64,15 +72,24 @@ |
64 | 72 | if (!psy->full_trig_name) |
65 | 73 | goto full_failed; |
66 | 74 | |
75 | + psy->charging_blink_full_solid_trig_name = kasprintf(GFP_KERNEL, | |
76 | + "%s-charging-blink-full-solid", psy->name); | |
77 | + if (!psy->charging_blink_full_solid_trig_name) | |
78 | + goto charging_blink_full_solid_failed; | |
79 | + | |
67 | 80 | led_trigger_register_simple(psy->charging_full_trig_name, |
68 | 81 | &psy->charging_full_trig); |
69 | 82 | led_trigger_register_simple(psy->charging_trig_name, |
70 | 83 | &psy->charging_trig); |
71 | 84 | led_trigger_register_simple(psy->full_trig_name, |
72 | 85 | &psy->full_trig); |
86 | + led_trigger_register_simple(psy->charging_blink_full_solid_trig_name, | |
87 | + &psy->charging_blink_full_solid_trig); | |
73 | 88 | |
74 | 89 | goto success; |
75 | 90 | |
91 | +charging_blink_full_solid_failed: | |
92 | + kfree(psy->full_trig_name); | |
76 | 93 | full_failed: |
77 | 94 | kfree(psy->charging_trig_name); |
78 | 95 | charging_failed: |
... | ... | @@ -88,6 +105,8 @@ |
88 | 105 | led_trigger_unregister_simple(psy->charging_full_trig); |
89 | 106 | led_trigger_unregister_simple(psy->charging_trig); |
90 | 107 | led_trigger_unregister_simple(psy->full_trig); |
108 | + led_trigger_unregister_simple(psy->charging_blink_full_solid_trig); | |
109 | + kfree(psy->charging_blink_full_solid_trig_name); | |
91 | 110 | kfree(psy->full_trig_name); |
92 | 111 | kfree(psy->charging_trig_name); |
93 | 112 | kfree(psy->charging_full_trig_name); |
drivers/power/power_supply_sysfs.c
... | ... | @@ -270,7 +270,7 @@ |
270 | 270 | attr = &power_supply_attrs[psy->properties[j]]; |
271 | 271 | |
272 | 272 | ret = power_supply_show_property(dev, attr, prop_buf); |
273 | - if (ret == -ENODEV) { | |
273 | + if (ret == -ENODEV || ret == -ENODATA) { | |
274 | 274 | /* When a battery is absent, we expect -ENODEV. Don't abort; |
275 | 275 | send the uevent with at least the the PRESENT=0 property */ |
276 | 276 | ret = 0; |
drivers/power/s3c_adc_battery.c
... | ... | @@ -406,8 +406,8 @@ |
406 | 406 | return 0; |
407 | 407 | } |
408 | 408 | #else |
409 | -#define s3c_adc_battery_suspend NULL | |
410 | -#define s3c_adc_battery_resume NULL | |
409 | +#define s3c_adc_bat_suspend NULL | |
410 | +#define s3c_adc_bat_resume NULL | |
411 | 411 | #endif |
412 | 412 | |
413 | 413 | static struct platform_driver s3c_adc_bat_driver = { |
drivers/power/twl4030_charger.c
... | ... | @@ -71,8 +71,11 @@ |
71 | 71 | struct power_supply usb; |
72 | 72 | struct otg_transceiver *transceiver; |
73 | 73 | struct notifier_block otg_nb; |
74 | + struct work_struct work; | |
74 | 75 | int irq_chg; |
75 | 76 | int irq_bci; |
77 | + | |
78 | + unsigned long event; | |
76 | 79 | }; |
77 | 80 | |
78 | 81 | /* |
79 | 82 | |
80 | 83 | |
... | ... | @@ -258,14 +261,11 @@ |
258 | 261 | return IRQ_HANDLED; |
259 | 262 | } |
260 | 263 | |
261 | -static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, | |
262 | - void *priv) | |
264 | +static void twl4030_bci_usb_work(struct work_struct *data) | |
263 | 265 | { |
264 | - struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb); | |
266 | + struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work); | |
265 | 267 | |
266 | - dev_dbg(bci->dev, "OTG notify %lu\n", val); | |
267 | - | |
268 | - switch (val) { | |
268 | + switch (bci->event) { | |
269 | 269 | case USB_EVENT_VBUS: |
270 | 270 | case USB_EVENT_CHARGER: |
271 | 271 | twl4030_charger_enable_usb(bci, true); |
272 | 272 | |
... | ... | @@ -274,7 +274,18 @@ |
274 | 274 | twl4030_charger_enable_usb(bci, false); |
275 | 275 | break; |
276 | 276 | } |
277 | +} | |
277 | 278 | |
279 | +static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, | |
280 | + void *priv) | |
281 | +{ | |
282 | + struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb); | |
283 | + | |
284 | + dev_dbg(bci->dev, "OTG notify %lu\n", val); | |
285 | + | |
286 | + bci->event = val; | |
287 | + schedule_work(&bci->work); | |
288 | + | |
278 | 289 | return NOTIFY_OK; |
279 | 290 | } |
280 | 291 | |
... | ... | @@ -465,6 +476,8 @@ |
465 | 476 | bci->irq_bci, ret); |
466 | 477 | goto fail_bci_irq; |
467 | 478 | } |
479 | + | |
480 | + INIT_WORK(&bci->work, twl4030_bci_usb_work); | |
468 | 481 | |
469 | 482 | bci->transceiver = otg_get_transceiver(); |
470 | 483 | if (bci->transceiver != NULL) { |
drivers/power/z2_battery.c
... | ... | @@ -134,6 +134,8 @@ |
134 | 134 | enum power_supply_property *prop; |
135 | 135 | struct z2_battery_info *info = charger->info; |
136 | 136 | |
137 | + if (info->charge_gpio >= 0) | |
138 | + props++; /* POWER_SUPPLY_PROP_STATUS */ | |
137 | 139 | if (info->batt_tech >= 0) |
138 | 140 | props++; /* POWER_SUPPLY_PROP_TECHNOLOGY */ |
139 | 141 | if (info->batt_I2C_reg >= 0) |
... | ... | @@ -293,6 +295,7 @@ |
293 | 295 | { "aer915", 0 }, |
294 | 296 | { } |
295 | 297 | }; |
298 | +MODULE_DEVICE_TABLE(i2c, z2_batt_id); | |
296 | 299 | |
297 | 300 | static struct i2c_driver z2_batt_driver = { |
298 | 301 | .driver = { |
include/linux/leds.h
... | ... | @@ -145,6 +145,9 @@ |
145 | 145 | extern void led_trigger_unregister_simple(struct led_trigger *trigger); |
146 | 146 | extern void led_trigger_event(struct led_trigger *trigger, |
147 | 147 | enum led_brightness event); |
148 | +extern void led_trigger_blink(struct led_trigger *trigger, | |
149 | + unsigned long *delay_on, | |
150 | + unsigned long *delay_off); | |
148 | 151 | |
149 | 152 | #else |
150 | 153 |
include/linux/power/bq20z75.h
1 | +/* | |
2 | + * Gas Gauge driver for TI's BQ20Z75 | |
3 | + * | |
4 | + * Copyright (c) 2010, NVIDIA Corporation. | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License as published by | |
8 | + * the Free Software Foundation; either version 2 of the License, or | |
9 | + * (at your option) any later version. | |
10 | + * | |
11 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | + * more details. | |
15 | + * | |
16 | + * You should have received a copy of the GNU General Public License along | |
17 | + * with this program; if not, write to the Free Software Foundation, Inc., | |
18 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | + */ | |
20 | + | |
21 | +#ifndef __LINUX_POWER_BQ20Z75_H_ | |
22 | +#define __LINUX_POWER_BQ20Z75_H_ | |
23 | + | |
24 | +#include <linux/power_supply.h> | |
25 | +#include <linux/types.h> | |
26 | + | |
27 | +/** | |
28 | + * struct bq20z75_platform_data - platform data for bq20z75 devices | |
29 | + * @battery_detect: GPIO which is used to detect battery presence | |
30 | + * @battery_detect_present: gpio state when battery is present (0 / 1) | |
31 | + * @i2c_retry_count: # of times to retry on i2c IO failure | |
32 | + */ | |
33 | +struct bq20z75_platform_data { | |
34 | + int battery_detect; | |
35 | + int battery_detect_present; | |
36 | + int i2c_retry_count; | |
37 | +}; | |
38 | + | |
39 | +#endif |
include/linux/power/bq27x00_battery.h
1 | +#ifndef __LINUX_BQ27X00_BATTERY_H__ | |
2 | +#define __LINUX_BQ27X00_BATTERY_H__ | |
3 | + | |
4 | +/** | |
5 | + * struct bq27000_plaform_data - Platform data for bq27000 devices | |
6 | + * @name: Name of the battery. If NULL the driver will fallback to "bq27000". | |
7 | + * @read: HDQ read callback. | |
8 | + * This function should provide access to the HDQ bus the battery is | |
9 | + * connected to. | |
10 | + * The first parameter is a pointer to the battery device, the second the | |
11 | + * register to be read. The return value should either be the content of | |
12 | + * the passed register or an error value. | |
13 | + */ | |
14 | +struct bq27000_platform_data { | |
15 | + const char *name; | |
16 | + int (*read)(struct device *dev, unsigned int); | |
17 | +}; | |
18 | + | |
19 | +#endif |
include/linux/power_supply.h
... | ... | @@ -173,6 +173,8 @@ |
173 | 173 | char *full_trig_name; |
174 | 174 | struct led_trigger *online_trig; |
175 | 175 | char *online_trig_name; |
176 | + struct led_trigger *charging_blink_full_solid_trig; | |
177 | + char *charging_blink_full_solid_trig_name; | |
176 | 178 | #endif |
177 | 179 | }; |
178 | 180 | |
... | ... | @@ -212,6 +214,51 @@ |
212 | 214 | |
213 | 215 | /* For APM emulation, think legacy userspace. */ |
214 | 216 | extern struct class *power_supply_class; |
217 | + | |
218 | +static inline bool power_supply_is_amp_property(enum power_supply_property psp) | |
219 | +{ | |
220 | + switch (psp) { | |
221 | + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | |
222 | + case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: | |
223 | + case POWER_SUPPLY_PROP_CHARGE_FULL: | |
224 | + case POWER_SUPPLY_PROP_CHARGE_EMPTY: | |
225 | + case POWER_SUPPLY_PROP_CHARGE_NOW: | |
226 | + case POWER_SUPPLY_PROP_CHARGE_AVG: | |
227 | + case POWER_SUPPLY_PROP_CHARGE_COUNTER: | |
228 | + case POWER_SUPPLY_PROP_CURRENT_MAX: | |
229 | + case POWER_SUPPLY_PROP_CURRENT_NOW: | |
230 | + case POWER_SUPPLY_PROP_CURRENT_AVG: | |
231 | + return 1; | |
232 | + default: | |
233 | + break; | |
234 | + } | |
235 | + | |
236 | + return 0; | |
237 | +} | |
238 | + | |
239 | +static inline bool power_supply_is_watt_property(enum power_supply_property psp) | |
240 | +{ | |
241 | + switch (psp) { | |
242 | + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | |
243 | + case POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN: | |
244 | + case POWER_SUPPLY_PROP_ENERGY_FULL: | |
245 | + case POWER_SUPPLY_PROP_ENERGY_EMPTY: | |
246 | + case POWER_SUPPLY_PROP_ENERGY_NOW: | |
247 | + case POWER_SUPPLY_PROP_ENERGY_AVG: | |
248 | + case POWER_SUPPLY_PROP_VOLTAGE_MAX: | |
249 | + case POWER_SUPPLY_PROP_VOLTAGE_MIN: | |
250 | + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | |
251 | + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | |
252 | + case POWER_SUPPLY_PROP_VOLTAGE_NOW: | |
253 | + case POWER_SUPPLY_PROP_VOLTAGE_AVG: | |
254 | + case POWER_SUPPLY_PROP_POWER_NOW: | |
255 | + return 1; | |
256 | + default: | |
257 | + break; | |
258 | + } | |
259 | + | |
260 | + return 0; | |
261 | +} | |
215 | 262 | |
216 | 263 | #endif /* __LINUX_POWER_SUPPLY_H__ */ |