summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorMayuresh Kulkarni <mkulkarni@nvidia.com>2010-09-29 17:43:49 +0530
committerBharat Nihalani <bnihalani@nvidia.com>2010-11-18 06:36:51 -0800
commita60c1aa9abde4e9b9345d8e29df92b831ede87bd (patch)
treed7372c925d06fbb5585a736afd3da06f22f454c2 /drivers/power
parentcfb26ef11de2e16cb7e3e4be2b60513323769a47 (diff)
power supply: bq20z75: fix misc bugs
- fixed bug due to which charging status was getting reported as dis-charging and vice-versa - poll the INIT bit in status register to be 0 which indicates init is done - handle status errors and return UNKNOWN for them Change-Id: I454be0b87964bae37a7fd44c7dd52f581884777d Reviewed-on: http://git-master/r/9900 Tested-by: Bharat Nihalani <bnihalani@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com> Reviewed-by: Nitin Kumbhar <nkumbhar@nvidia.com> Tested-by: Nitin Kumbhar <nkumbhar@nvidia.com> Reviewed-by: Mayuresh Kulkarni <mkulkarni@nvidia.com> Reviewed-by: Thomas Cherry <tcherry@nvidia.com>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/bq20z75_battery.c132
1 files changed, 81 insertions, 51 deletions
diff --git a/drivers/power/bq20z75_battery.c b/drivers/power/bq20z75_battery.c
index e102de4c7809..1452f3f20d18 100644
--- a/drivers/power/bq20z75_battery.c
+++ b/drivers/power/bq20z75_battery.c
@@ -51,9 +51,10 @@ enum {
#define MANUFACTURER_ACCESS_SLEEP 0x0011
/* battery status value bits */
-#define BATTERY_CHARGING 0x40
+#define BATTERY_INIT_DONE 0x80
+#define BATTERY_DISCHARGING 0x40
#define BATTERY_FULL_CHARGED 0x20
-#define BATTERY_FULL_DISCHARGED 0x10
+#define BATTERY_FULL_DISCHARGED 0x10
#define BQ20Z75_DATA(_psp, _addr, _min_value, _max_value) \
{ \
@@ -152,8 +153,7 @@ static int bq20z75_get_health(enum power_supply_property psp,
val->intval = 0;
else
val->intval = 1;
- }
- else if (psp == POWER_SUPPLY_PROP_HEALTH) {
+ } else if (psp == POWER_SUPPLY_PROP_HEALTH) {
if (ret == 0x09)
val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
else if (ret == 0x0B)
@@ -175,6 +175,7 @@ static int bq20z75_get_psp(int reg_offset, enum power_supply_property psp,
{
s32 ret;
+recheck:
ret = i2c_smbus_read_word_data(bq20z75_device->client,
bq20z75_data[reg_offset].addr);
if (ret < 0) {
@@ -190,20 +191,32 @@ static int bq20z75_get_psp(int reg_offset, enum power_supply_property psp,
/* mask the upper byte and then find the
* actual status */
ret &= 0x00FF;
- if (ret & BATTERY_CHARGING)
- val->intval = POWER_SUPPLY_STATUS_CHARGING;
+
+ /* check the error conditions
+ * lower nibble represent error
+ * 0 = no error, so check the remaining bits
+ * != 0 means error so return */
+ if ((ret & 0x000F) >= 0x01) {
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ return 0;
+ }
+
+ while (!(ret & BATTERY_INIT_DONE))
+ goto recheck;
+
+ if (ret & BATTERY_DISCHARGING)
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
else if (ret & BATTERY_FULL_CHARGED)
val->intval = POWER_SUPPLY_STATUS_FULL;
else if (ret & BATTERY_FULL_DISCHARGED)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
- else
- val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ else if (!(ret & BATTERY_DISCHARGING))
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
}
/* bq20z75 provides battery tempreture in 0.1°K
* so convert it to °C */
- else if (psp == POWER_SUPPLY_PROP_TEMP) {
+ else if (psp == POWER_SUPPLY_PROP_TEMP)
val->intval = ret - 2731;
- }
} else {
val->intval = 0;
if (psp == POWER_SUPPLY_PROP_STATUS)
@@ -232,6 +245,22 @@ static int bq20z75_get_capacity(union power_supply_propval *val)
return 0;
}
+static char bq20z75_serial[5];
+static int bq20z75_get_battery_serial_number(union power_supply_propval *val)
+{
+ int ret;
+
+ ret = i2c_smbus_read_word_data(bq20z75_device->client,
+ bq20z75_data[REG_SERIAL_NUMBER].addr);
+ if (ret < 0)
+ return ret;
+
+ ret = sprintf(bq20z75_serial, "%04x", ret);
+ val->strval = bq20z75_serial;
+
+ return 0;
+}
+
static int bq20z75_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -239,42 +268,46 @@ static int bq20z75_get_property(struct power_supply *psy,
u8 count;
switch (psp) {
- case POWER_SUPPLY_PROP_PRESENT:
- case POWER_SUPPLY_PROP_HEALTH:
- if (bq20z75_get_health(psp, val))
- return -EINVAL;
- break;
-
- case POWER_SUPPLY_PROP_TECHNOLOGY:
- val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
- break;
-
- case POWER_SUPPLY_PROP_CAPACITY:
- if (bq20z75_get_capacity(val))
- return -EINVAL;
- break;
-
- case POWER_SUPPLY_PROP_STATUS:
- case POWER_SUPPLY_PROP_CYCLE_COUNT:
- case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- case POWER_SUPPLY_PROP_CURRENT_NOW:
- case POWER_SUPPLY_PROP_TEMP:
- case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
- case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
- case POWER_SUPPLY_PROP_SERIAL_NUMBER:
- for (count = 0; count < REG_MAX; count++) {
- if (psp == bq20z75_data[count].psp)
- break;
- }
+ case POWER_SUPPLY_PROP_PRESENT:
+ case POWER_SUPPLY_PROP_HEALTH:
+ if (bq20z75_get_health(psp, val))
+ return -EINVAL;
+ break;
- if (bq20z75_get_psp(count, psp, val))
- return -EINVAL;
- break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
- default:
- dev_err(&bq20z75_device->client->dev,
- "%s: INVALID property\n", __func__);
+ case POWER_SUPPLY_PROP_CAPACITY:
+ if (bq20z75_get_capacity(val))
return -EINVAL;
+ break;
+
+ case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+ if (bq20z75_get_battery_serial_number(val))
+ return -EINVAL;
+ break;
+
+ case POWER_SUPPLY_PROP_STATUS:
+ case POWER_SUPPLY_PROP_CYCLE_COUNT:
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ case POWER_SUPPLY_PROP_TEMP:
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+ case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+ for (count = 0; count < REG_MAX; count++) {
+ if (psp == bq20z75_data[count].psp)
+ break;
+ }
+
+ if (bq20z75_get_psp(count, psp, val))
+ return -EINVAL;
+ break;
+
+ default:
+ dev_err(&bq20z75_device->client->dev,
+ "%s: INVALID property\n", __func__);
+ return -EINVAL;
}
return 0;
@@ -286,9 +319,9 @@ static int bq20z75_probe(struct i2c_client *client,
int rc;
bq20z75_device = kzalloc(sizeof(*bq20z75_device), GFP_KERNEL);
- if (!bq20z75_device) {
+ if (!bq20z75_device)
return -ENOMEM;
- }
+
memset(bq20z75_device, 0, sizeof(*bq20z75_device));
bq20z75_device->client = client;
@@ -314,10 +347,7 @@ static int bq20z75_remove(struct i2c_client *client)
bq20z75_device = i2c_get_clientdata(client);
power_supply_unregister(&bq20z75_supply);
- if (bq20z75_device) {
- kfree(bq20z75_device);
- bq20z75_device = NULL;
- }
+ kfree(bq20z75_device);
return 0;
}
@@ -359,10 +389,10 @@ static const struct i2c_device_id bq20z75_id[] = {
static struct i2c_driver bq20z75_battery_driver = {
.probe = bq20z75_probe,
- .remove = bq20z75_remove,
+ .remove = bq20z75_remove,
#if defined (CONFIG_PM)
.suspend = bq20z75_suspend,
- .resume = bq20z75_resume,
+ .resume = bq20z75_resume,
#endif
.id_table = bq20z75_id,
.driver = {