aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/bq20z75.c
diff options
context:
space:
mode:
authorRhyland Klein <rklein@nvidia.com>2011-02-28 19:55:28 -0500
committerAnton Vorontsov <cbouatmailru@gmail.com>2011-03-01 14:24:01 -0500
commitbb879101606dd7235d8f4ecd0f707b63281d0838 (patch)
tree74aae7149b888a1e54f23608314f795ee992d47f /drivers/power/bq20z75.c
parentb5db7cde69f87178fb771970a2b512a452a9d680 (diff)
bq20z75: Add optional battery detect gpio
Adding support for an optional gpio for battery detection. This is passed in through the i2c platform data. It also accepts another field, battery_detect_present to signify the gpio state which means the battery is present, either 0 (low) or 1 (high). Signed-off-by: Rhyland Klein <rklein@nvidia.com> Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
Diffstat (limited to 'drivers/power/bq20z75.c')
-rw-r--r--drivers/power/bq20z75.c160
1 files changed, 129 insertions, 31 deletions
diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c
index 4141775e5ff6..a51e98d74d34 100644
--- a/drivers/power/bq20z75.c
+++ b/drivers/power/bq20z75.c
@@ -25,6 +25,10 @@
25#include <linux/power_supply.h> 25#include <linux/power_supply.h>
26#include <linux/i2c.h> 26#include <linux/i2c.h>
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/interrupt.h>
29#include <linux/gpio.h>
30
31#include <linux/power/bq20z75.h>
28 32
29enum { 33enum {
30 REG_MANUFACTURER_DATA, 34 REG_MANUFACTURER_DATA,
@@ -141,8 +145,13 @@ static enum power_supply_property bq20z75_properties[] = {
141}; 145};
142 146
143struct bq20z75_info { 147struct bq20z75_info {
144 struct i2c_client *client; 148 struct i2c_client *client;
145 struct power_supply power_supply; 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;
146}; 155};
147 156
148static int bq20z75_read_word_data(struct i2c_client *client, u8 address) 157static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
@@ -179,6 +188,18 @@ static int bq20z75_get_battery_presence_and_health(
179 union power_supply_propval *val) 188 union power_supply_propval *val)
180{ 189{
181 s32 ret; 190 s32 ret;
191 struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
192
193 if (psp == POWER_SUPPLY_PROP_PRESENT &&
194 bq20z75_device->gpio_detect) {
195 ret = gpio_get_value(
196 bq20z75_device->pdata->battery_detect);
197 if (ret == bq20z75_device->pdata->battery_detect_present)
198 val->intval = 1;
199 else
200 val->intval = 0;
201 return ret;
202 }
182 203
183 /* Write to ManufacturerAccess with 204 /* Write to ManufacturerAccess with
184 * ManufacturerAccess command and then 205 * ManufacturerAccess command and then
@@ -192,8 +213,11 @@ static int bq20z75_get_battery_presence_and_health(
192 213
193 ret = bq20z75_read_word_data(client, 214 ret = bq20z75_read_word_data(client,
194 bq20z75_data[REG_MANUFACTURER_DATA].addr); 215 bq20z75_data[REG_MANUFACTURER_DATA].addr);
195 if (ret < 0) 216 if (ret < 0) {
217 if (psp == POWER_SUPPLY_PROP_PRESENT)
218 val->intval = 0; /* battery removed */
196 return ret; 219 return ret;
220 }
197 221
198 if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value || 222 if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value ||
199 ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) { 223 ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) {
@@ -397,8 +421,7 @@ static int bq20z75_get_property(struct power_supply *psy,
397 enum power_supply_property psp, 421 enum power_supply_property psp,
398 union power_supply_propval *val) 422 union power_supply_propval *val)
399{ 423{
400 int ps_index; 424 int ret = 0;
401 int ret;
402 struct bq20z75_info *bq20z75_device = container_of(psy, 425 struct bq20z75_info *bq20z75_device = container_of(psy,
403 struct bq20z75_info, power_supply); 426 struct bq20z75_info, power_supply);
404 struct i2c_client *client = bq20z75_device->client; 427 struct i2c_client *client = bq20z75_device->client;
@@ -407,8 +430,6 @@ static int bq20z75_get_property(struct power_supply *psy,
407 case POWER_SUPPLY_PROP_PRESENT: 430 case POWER_SUPPLY_PROP_PRESENT:
408 case POWER_SUPPLY_PROP_HEALTH: 431 case POWER_SUPPLY_PROP_HEALTH:
409 ret = bq20z75_get_battery_presence_and_health(client, psp, val); 432 ret = bq20z75_get_battery_presence_and_health(client, psp, val);
410 if (ret)
411 return ret;
412 break; 433 break;
413 434
414 case POWER_SUPPLY_PROP_TECHNOLOGY: 435 case POWER_SUPPLY_PROP_TECHNOLOGY:
@@ -422,20 +443,15 @@ static int bq20z75_get_property(struct power_supply *psy,
422 case POWER_SUPPLY_PROP_CHARGE_FULL: 443 case POWER_SUPPLY_PROP_CHARGE_FULL:
423 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 444 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
424 case POWER_SUPPLY_PROP_CAPACITY: 445 case POWER_SUPPLY_PROP_CAPACITY:
425 ps_index = bq20z75_get_property_index(client, psp); 446 ret = bq20z75_get_property_index(client, psp);
426 if (ps_index < 0) 447 if (ret < 0)
427 return ps_index; 448 break;
428
429 ret = bq20z75_get_battery_capacity(client, ps_index, psp, val);
430 if (ret)
431 return ret;
432 449
450 ret = bq20z75_get_battery_capacity(client, ret, psp, val);
433 break; 451 break;
434 452
435 case POWER_SUPPLY_PROP_SERIAL_NUMBER: 453 case POWER_SUPPLY_PROP_SERIAL_NUMBER:
436 ret = bq20z75_get_battery_serial_number(client, val); 454 ret = bq20z75_get_battery_serial_number(client, val);
437 if (ret)
438 return ret;
439 break; 455 break;
440 456
441 case POWER_SUPPLY_PROP_STATUS: 457 case POWER_SUPPLY_PROP_STATUS:
@@ -446,14 +462,11 @@ static int bq20z75_get_property(struct power_supply *psy,
446 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 462 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
447 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: 463 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
448 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 464 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
449 ps_index = bq20z75_get_property_index(client, psp); 465 ret = bq20z75_get_property_index(client, psp);
450 if (ps_index < 0) 466 if (ret < 0)
451 return ps_index; 467 break;
452
453 ret = bq20z75_get_battery_property(client, ps_index, psp, val);
454 if (ret)
455 return ret;
456 468
469 ret = bq20z75_get_battery_property(client, ret, psp, val);
457 break; 470 break;
458 471
459 default: 472 default:
@@ -462,26 +475,51 @@ static int bq20z75_get_property(struct power_supply *psy,
462 return -EINVAL; 475 return -EINVAL;
463 } 476 }
464 477
465 /* Convert units to match requirements for power supply class */ 478 if (!bq20z75_device->enable_detection)
466 bq20z75_unit_adjustment(client, psp, val); 479 goto done;
480
481 if (!bq20z75_device->gpio_detect &&
482 bq20z75_device->is_present != (ret >= 0)) {
483 bq20z75_device->is_present = (ret >= 0);
484 power_supply_changed(&bq20z75_device->power_supply);
485 }
486
487done:
488 if (!ret) {
489 /* Convert units to match requirements for power supply class */
490 bq20z75_unit_adjustment(client, psp, val);
491 }
467 492
468 dev_dbg(&client->dev, 493 dev_dbg(&client->dev,
469 "%s: property = %d, value = %d\n", __func__, psp, val->intval); 494 "%s: property = %d, value = %d\n", __func__, psp, val->intval);
470 495
471 return 0; 496 return ret;
472} 497}
473 498
474static int bq20z75_probe(struct i2c_client *client, 499static irqreturn_t bq20z75_irq(int irq, void *devid)
500{
501 struct power_supply *battery = devid;
502
503 power_supply_changed(battery);
504
505 return IRQ_HANDLED;
506}
507
508static int __devinit bq20z75_probe(struct i2c_client *client,
475 const struct i2c_device_id *id) 509 const struct i2c_device_id *id)
476{ 510{
477 struct bq20z75_info *bq20z75_device; 511 struct bq20z75_info *bq20z75_device;
512 struct bq20z75_platform_data *pdata = client->dev.platform_data;
478 int rc; 513 int rc;
514 int irq;
479 515
480 bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL); 516 bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL);
481 if (!bq20z75_device) 517 if (!bq20z75_device)
482 return -ENOMEM; 518 return -ENOMEM;
483 519
484 bq20z75_device->client = client; 520 bq20z75_device->client = client;
521 bq20z75_device->enable_detection = false;
522 bq20z75_device->gpio_detect = false;
485 bq20z75_device->power_supply.name = "battery"; 523 bq20z75_device->power_supply.name = "battery";
486 bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY; 524 bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
487 bq20z75_device->power_supply.properties = bq20z75_properties; 525 bq20z75_device->power_supply.properties = bq20z75_properties;
@@ -489,26 +527,86 @@ static int bq20z75_probe(struct i2c_client *client,
489 ARRAY_SIZE(bq20z75_properties); 527 ARRAY_SIZE(bq20z75_properties);
490 bq20z75_device->power_supply.get_property = bq20z75_get_property; 528 bq20z75_device->power_supply.get_property = bq20z75_get_property;
491 529
530 if (pdata) {
531 bq20z75_device->gpio_detect =
532 gpio_is_valid(pdata->battery_detect);
533 bq20z75_device->pdata = pdata;
534 }
535
492 i2c_set_clientdata(client, bq20z75_device); 536 i2c_set_clientdata(client, bq20z75_device);
493 537
538 if (!bq20z75_device->gpio_detect)
539 goto skip_gpio;
540
541 rc = gpio_request(pdata->battery_detect, dev_name(&client->dev));
542 if (rc) {
543 dev_warn(&client->dev, "Failed to request gpio: %d\n", rc);
544 bq20z75_device->gpio_detect = false;
545 goto skip_gpio;
546 }
547
548 rc = gpio_direction_input(pdata->battery_detect);
549 if (rc) {
550 dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc);
551 gpio_free(pdata->battery_detect);
552 bq20z75_device->gpio_detect = false;
553 goto skip_gpio;
554 }
555
556 irq = gpio_to_irq(pdata->battery_detect);
557 if (irq <= 0) {
558 dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
559 gpio_free(pdata->battery_detect);
560 bq20z75_device->gpio_detect = false;
561 goto skip_gpio;
562 }
563
564 rc = request_irq(irq, bq20z75_irq,
565 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
566 dev_name(&client->dev), &bq20z75_device->power_supply);
567 if (rc) {
568 dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
569 gpio_free(pdata->battery_detect);
570 bq20z75_device->gpio_detect = false;
571 goto skip_gpio;
572 }
573
574 bq20z75_device->irq = irq;
575
576skip_gpio:
577
494 rc = power_supply_register(&client->dev, &bq20z75_device->power_supply); 578 rc = power_supply_register(&client->dev, &bq20z75_device->power_supply);
495 if (rc) { 579 if (rc) {
496 dev_err(&client->dev, 580 dev_err(&client->dev,
497 "%s: Failed to register power supply\n", __func__); 581 "%s: Failed to register power supply\n", __func__);
498 kfree(bq20z75_device); 582 goto exit_psupply;
499 return rc;
500 } 583 }
501 584
502 dev_info(&client->dev, 585 dev_info(&client->dev,
503 "%s: battery gas gauge device registered\n", client->name); 586 "%s: battery gas gauge device registered\n", client->name);
504 587
505 return 0; 588 return 0;
589
590exit_psupply:
591 if (bq20z75_device->irq)
592 free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
593 if (bq20z75_device->gpio_detect)
594 gpio_free(pdata->battery_detect);
595
596 kfree(bq20z75_device);
597
598 return rc;
506} 599}
507 600
508static int bq20z75_remove(struct i2c_client *client) 601static int __devexit bq20z75_remove(struct i2c_client *client)
509{ 602{
510 struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); 603 struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
511 604
605 if (bq20z75_device->irq)
606 free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
607 if (bq20z75_device->gpio_detect)
608 gpio_free(bq20z75_device->pdata->battery_detect);
609
512 power_supply_unregister(&bq20z75_device->power_supply); 610 power_supply_unregister(&bq20z75_device->power_supply);
513 kfree(bq20z75_device); 611 kfree(bq20z75_device);
514 bq20z75_device = NULL; 612 bq20z75_device = NULL;
@@ -544,7 +642,7 @@ static const struct i2c_device_id bq20z75_id[] = {
544 642
545static struct i2c_driver bq20z75_battery_driver = { 643static struct i2c_driver bq20z75_battery_driver = {
546 .probe = bq20z75_probe, 644 .probe = bq20z75_probe,
547 .remove = bq20z75_remove, 645 .remove = __devexit_p(bq20z75_remove),
548 .suspend = bq20z75_suspend, 646 .suspend = bq20z75_suspend,
549 .resume = bq20z75_resume, 647 .resume = bq20z75_resume,
550 .id_table = bq20z75_id, 648 .id_table = bq20z75_id,