diff options
-rw-r--r-- | drivers/power/bq27x00_battery.c | 58 |
1 files changed, 53 insertions, 5 deletions
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index dbe3fcb3b0ba..25350fcbadb3 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c | |||
@@ -74,10 +74,13 @@ struct bq27x00_device_info { | |||
74 | 74 | ||
75 | struct bq27x00_reg_cache cache; | 75 | struct bq27x00_reg_cache cache; |
76 | unsigned long last_update; | 76 | unsigned long last_update; |
77 | struct delayed_work work; | ||
77 | 78 | ||
78 | struct power_supply bat; | 79 | struct power_supply bat; |
79 | 80 | ||
80 | struct bq27x00_access_methods bus; | 81 | struct bq27x00_access_methods bus; |
82 | |||
83 | struct mutex lock; | ||
81 | }; | 84 | }; |
82 | 85 | ||
83 | static enum power_supply_property bq27x00_battery_props[] = { | 86 | static enum power_supply_property bq27x00_battery_props[] = { |
@@ -93,6 +96,11 @@ static enum power_supply_property bq27x00_battery_props[] = { | |||
93 | POWER_SUPPLY_PROP_TECHNOLOGY, | 96 | POWER_SUPPLY_PROP_TECHNOLOGY, |
94 | }; | 97 | }; |
95 | 98 | ||
99 | static unsigned int poll_interval = 360; | ||
100 | module_param(poll_interval, uint, 0644); | ||
101 | MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ | ||
102 | "0 disables polling"); | ||
103 | |||
96 | /* | 104 | /* |
97 | * Common code for BQ27x00 devices | 105 | * Common code for BQ27x00 devices |
98 | */ | 106 | */ |
@@ -169,6 +177,21 @@ static void bq27x00_update(struct bq27x00_device_info *di) | |||
169 | di->last_update = jiffies; | 177 | di->last_update = jiffies; |
170 | } | 178 | } |
171 | 179 | ||
180 | static void bq27x00_battery_poll(struct work_struct *work) | ||
181 | { | ||
182 | struct bq27x00_device_info *di = | ||
183 | container_of(work, struct bq27x00_device_info, work.work); | ||
184 | |||
185 | bq27x00_update(di); | ||
186 | |||
187 | if (poll_interval > 0) { | ||
188 | /* The timer does not have to be accurate. */ | ||
189 | set_timer_slack(&di->work.timer, poll_interval * HZ / 4); | ||
190 | schedule_delayed_work(&di->work, poll_interval * HZ); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | |||
172 | /* | 195 | /* |
173 | * Return the battery temperature in tenths of degree Celsius | 196 | * Return the battery temperature in tenths of degree Celsius |
174 | * Or < 0 if something fails. | 197 | * Or < 0 if something fails. |
@@ -283,8 +306,12 @@ static int bq27x00_battery_get_property(struct power_supply *psy, | |||
283 | int ret = 0; | 306 | int ret = 0; |
284 | struct bq27x00_device_info *di = to_bq27x00_device_info(psy); | 307 | struct bq27x00_device_info *di = to_bq27x00_device_info(psy); |
285 | 308 | ||
286 | if (time_is_before_jiffies(di->last_update + 5 * HZ)) | 309 | mutex_lock(&di->lock); |
287 | bq27x00_update(di); | 310 | if (time_is_before_jiffies(di->last_update + 5 * HZ)) { |
311 | cancel_delayed_work_sync(&di->work); | ||
312 | bq27x00_battery_poll(&di->work.work); | ||
313 | } | ||
314 | mutex_unlock(&di->lock); | ||
288 | 315 | ||
289 | if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) | 316 | if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) |
290 | return -ENODEV; | 317 | return -ENODEV; |
@@ -327,6 +354,14 @@ static int bq27x00_battery_get_property(struct power_supply *psy, | |||
327 | return ret; | 354 | return ret; |
328 | } | 355 | } |
329 | 356 | ||
357 | static void bq27x00_external_power_changed(struct power_supply *psy) | ||
358 | { | ||
359 | struct bq27x00_device_info *di = to_bq27x00_device_info(psy); | ||
360 | |||
361 | cancel_delayed_work_sync(&di->work); | ||
362 | schedule_delayed_work(&di->work, 0); | ||
363 | } | ||
364 | |||
330 | static int bq27x00_powersupply_init(struct bq27x00_device_info *di) | 365 | static int bq27x00_powersupply_init(struct bq27x00_device_info *di) |
331 | { | 366 | { |
332 | int ret; | 367 | int ret; |
@@ -335,7 +370,10 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di) | |||
335 | di->bat.properties = bq27x00_battery_props; | 370 | di->bat.properties = bq27x00_battery_props; |
336 | di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); | 371 | di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); |
337 | di->bat.get_property = bq27x00_battery_get_property; | 372 | di->bat.get_property = bq27x00_battery_get_property; |
338 | di->bat.external_power_changed = NULL; | 373 | di->bat.external_power_changed = bq27x00_external_power_changed; |
374 | |||
375 | INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll); | ||
376 | mutex_init(&di->lock); | ||
339 | 377 | ||
340 | ret = power_supply_register(di->dev, &di->bat); | 378 | ret = power_supply_register(di->dev, &di->bat); |
341 | if (ret) { | 379 | if (ret) { |
@@ -350,6 +388,15 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di) | |||
350 | return 0; | 388 | return 0; |
351 | } | 389 | } |
352 | 390 | ||
391 | static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di) | ||
392 | { | ||
393 | cancel_delayed_work_sync(&di->work); | ||
394 | |||
395 | power_supply_unregister(&di->bat); | ||
396 | |||
397 | mutex_destroy(&di->lock); | ||
398 | } | ||
399 | |||
353 | 400 | ||
354 | /* i2c specific code */ | 401 | /* i2c specific code */ |
355 | #ifdef CONFIG_BATTERY_BQ27X00_I2C | 402 | #ifdef CONFIG_BATTERY_BQ27X00_I2C |
@@ -457,7 +504,7 @@ static int bq27x00_battery_remove(struct i2c_client *client) | |||
457 | { | 504 | { |
458 | struct bq27x00_device_info *di = i2c_get_clientdata(client); | 505 | struct bq27x00_device_info *di = i2c_get_clientdata(client); |
459 | 506 | ||
460 | power_supply_unregister(&di->bat); | 507 | bq27x00_powersupply_unregister(di); |
461 | 508 | ||
462 | kfree(di->bat.name); | 509 | kfree(di->bat.name); |
463 | 510 | ||
@@ -590,7 +637,8 @@ static int __devexit bq27000_battery_remove(struct platform_device *pdev) | |||
590 | { | 637 | { |
591 | struct bq27x00_device_info *di = platform_get_drvdata(pdev); | 638 | struct bq27x00_device_info *di = platform_get_drvdata(pdev); |
592 | 639 | ||
593 | power_supply_unregister(&di->bat); | 640 | bq27x00_powersupply_unregister(di); |
641 | |||
594 | platform_set_drvdata(pdev, NULL); | 642 | platform_set_drvdata(pdev, NULL); |
595 | kfree(di); | 643 | kfree(di); |
596 | 644 | ||