summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorPritesh Raithatha <praithatha@nvidia.com>2011-09-06 20:49:21 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:49:14 -0800
commitd908d011882fab1e808af52216d39be206cc610f (patch)
treed838d188a5402ee0fac1f4d3abafd0f9fd2c6891 /drivers/power
parente823650a20d12e5a993375d198d3016c4aec86dd (diff)
power: bq27x00: added i2c write and ctrl_read functions.
-Removes compilation errors of missing i2c client. -Driver was using mix of i2c_transfer and smbus read/write and not using any locking mechanism to serialize it. Due to that when they are called simultaneously, it gives garbage data. If it is reading temperature and is out of range than android will shutdown the device. -Added i2c write and ctrl_read functions. -Replaced smbus read/write with related i2c_transfer functions. Bug 872590 Reviewed-on: http://git-master/r/#change,50858 (cherry picked from commit 403577f6741987457821035ba2822f75116032b5) Change-Id: I95f3506efb335aa82ce6ebce69363d4226fe7696 Signed-off-by: Pritesh Raithatha <praithatha@nvidia.com> Reviewed-on: http://git-master/r/56610 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: Rdf1fb7dc797aa4c47ef13a907e841a2608d2922f
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/bq27x00_battery.c198
1 files changed, 126 insertions, 72 deletions
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 3fede6541e6f..355fb2b673dc 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -5,6 +5,7 @@
* Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
* Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
* Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2011 NVIDIA Corporation.
*
* Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
*
@@ -72,6 +73,7 @@
#define BQ27510_ENERGY_AVAIL 0x22
#define BQ27510_POWER_AVG 0x24
#define BQ27510_CYCLE_COUNT 0x2a
+
/* bq27510-g2 control register sub-commands*/
#define BQ27510_CNTL_DEVICE_TYPE 0x0001
#define BQ27510_CNTL_SET_SLEEP 0x0013
@@ -81,6 +83,10 @@
struct bq27x00_device_info;
struct bq27x00_access_methods {
int (*read)(struct bq27x00_device_info *di, u8 reg, bool single);
+ int (*ctrl_read)(struct bq27x00_device_info *di, u8 ctrl_reg,
+ u16 ctrl_func_reg);
+ int (*write)(struct bq27x00_device_info *di, u8 reg, u16 val,
+ bool single);
};
enum bq27x00_chip { BQ27000, BQ27500, BQ27510 };
@@ -153,26 +159,38 @@ static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg,
return di->bus.read(di, reg, single);
}
+static inline int bq27x00_ctrl_read(struct bq27x00_device_info *di,
+ u8 ctrl_reg, u16 ctrl_func_reg)
+{
+ return di->bus.ctrl_read(di, ctrl_reg, ctrl_func_reg);
+}
+
+static inline int bq27x00_write(struct bq27x00_device_info *di, u8 reg,
+ u16 val, bool single)
+{
+ return di->bus.write(di, reg, val, single);
+}
+
static int bq27510_battery_health(struct bq27x00_device_info *di,
- int reg_offset)
+ union power_supply_propval *val)
{
int ret;
- int status;
- if (di->chip == BQ27500 || di->chip == BQ27510) {
- ret = i2c_smbus_read_word_data(di->client, reg_offset);
- if (ret < 0) {
+ if ((di->chip == BQ27500) || (di->chip == BQ27510)) {
+ ret = bq27x00_read(di, BQ27x00_REG_FLAGS, false);
+ if (ret < 0) {
dev_err(di->dev, "read failure\n");
return ret;
}
if (ret & BQ27500_FLAG_SOCF)
- status = POWER_SUPPLY_HEALTH_DEAD;
+ val->intval = POWER_SUPPLY_HEALTH_DEAD;
else if (ret & BQ27500_FLAG_OTC)
- status = POWER_SUPPLY_HEALTH_OVERHEAT;
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
else
- status = POWER_SUPPLY_HEALTH_GOOD;
- return status;
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+
+ return 0;
}
return -1;
@@ -186,7 +204,7 @@ static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di)
{
int rsoc;
- if (di->chip == BQ27500)
+ if ((di->chip == BQ27500) || (di->chip == BQ27510))
rsoc = bq27x00_read(di, BQ27500_REG_SOC, false);
else
rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true);
@@ -245,7 +263,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
{
int ilmd;
- if (di->chip == BQ27500)
+ if ((di->chip == BQ27500) || (di->chip == BQ27510))
ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false);
else
ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true);
@@ -255,7 +273,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
return ilmd;
}
- if (di->chip == BQ27500)
+ if ((di->chip == BQ27500) || (di->chip == BQ27510))
ilmd *= 1000;
else
ilmd = ilmd * 256 * 3570 / BQ27000_RS;
@@ -374,15 +392,15 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di,
{
int curr;
- if (di->chip == BQ27500)
- curr = bq27x00_read(di, BQ27x00_REG_AI, false);
+ if ((di->chip == BQ27500) || (di->chip == BQ27510))
+ curr = bq27x00_read(di, BQ27x00_REG_AI, false);
else
- curr = di->cache.current_now;
+ curr = di->cache.current_now;
if (curr < 0)
return curr;
- if (di->chip == BQ27500) {
+ if ((di->chip == BQ27500) || (di->chip == BQ27510)) {
/* bq27500 returns signed value */
val->intval = (int)((s16)curr) * 1000;
} else {
@@ -458,7 +476,7 @@ static int bq27x00_battery_energy(struct bq27x00_device_info *di,
return ae;
}
- if (di->chip == BQ27500)
+ if ((di->chip == BQ27500) || (di->chip == BQ27510))
ae *= 1000;
else
ae = ae * 29200 / BQ27000_RS;
@@ -485,12 +503,18 @@ static int bq27510_battery_present(struct bq27x00_device_info *di,
{
int ret;
- ret = i2c_smbus_read_word_data(di->client, BQ27x00_REG_FLAGS);
- if (!(ret & BQ27500_FLAG_BAT_DET))
- val->intval = 0;
- else
+ ret = bq27x00_read(di, BQ27x00_REG_FLAGS, false);
+ if (ret < 0) {
+ dev_err(di->dev, "error reading flags\n");
+ return ret;
+ }
+
+ if (ret & BQ27500_FLAG_BAT_DET)
val->intval = 1;
- return val->intval;
+ else
+ val->intval = 0;
+
+ return 0;
}
static char bq27510_serial[5];
@@ -500,18 +524,8 @@ static int bq27510_get_battery_serial_number(struct bq27x00_device_info *di,
int ret;
if (di->chip == BQ27510) {
- ret = i2c_smbus_write_word_data(di->client, BQ27510_CNTL,
+ ret = bq27x00_ctrl_read(di, BQ27510_CNTL,
BQ27510_CNTL_DEVICE_TYPE);
- if (ret < 0) {
- dev_err(di->dev, "write failure\n");
- return ret;
- }
- ret = i2c_smbus_read_word_data(di->client, 0x00);
- if (ret < 0) {
- dev_err(di->dev, "read failure\n");
- return ret;
- }
-
ret = sprintf(bq27510_serial, "%04x", ret);
val->strval = bq27510_serial;
return 0;
@@ -521,12 +535,19 @@ static int bq27510_get_battery_serial_number(struct bq27x00_device_info *di,
}
static int bq27510_battery_power_avg(struct bq27x00_device_info *di,
- int reg_offset)
+ union power_supply_propval *val)
{
- if (di->chip == BQ27510)
- return i2c_smbus_read_word_data(di->client, reg_offset);
- else
+ int ret;
+ if (di->chip == BQ27510) {
+ ret = bq27x00_read(di, BQ27510_POWER_AVG, false);
+ if (ret < 0) {
+ dev_err(di->dev, "read failure\n");
+ return ret;
+ }
+ val->intval = ret;
return 0;
+ }
+ return -1;
}
static int bq27510_battery_cycle_count(struct bq27x00_device_info *di,
@@ -535,8 +556,8 @@ static int bq27510_battery_cycle_count(struct bq27x00_device_info *di,
int ret;
if (di->chip == BQ27510) {
- ret = i2c_smbus_read_word_data(di->client, reg_offset);
- if (ret < 0)
+ ret = bq27x00_read(di, reg_offset, false);
+ if (ret < 0)
dev_err(di->dev, "read failure\n");
return ret;
} else {
@@ -572,7 +593,7 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
ret = bq27x00_battery_voltage(di, val);
break;
case POWER_SUPPLY_PROP_PRESENT:
- val->intval = bq27510_battery_present(di, val);
+ ret = bq27510_battery_present(di, val);
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = bq27x00_battery_current(di, val);
@@ -611,8 +632,7 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
ret = bq27x00_battery_energy(di, val);
break;
case POWER_SUPPLY_PROP_POWER_AVG:
- val->intval = bq27510_battery_power_avg(di,
- BQ27510_POWER_AVG);
+ ret = bq27510_battery_power_avg(di, val);
break;
case POWER_SUPPLY_PROP_CYCLE_COUNT:
val->intval = bq27510_battery_cycle_count(di,
@@ -623,7 +643,7 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
return -EINVAL;
break;
case POWER_SUPPLY_PROP_HEALTH:
- val->intval = bq27510_battery_health(di, BQ27x00_REG_FLAGS);
+ ret = bq27510_battery_health(di, val);
break;
default:
return -EINVAL;
@@ -719,6 +739,48 @@ static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, bool single)
return ret;
}
+static int bq27x00_write_i2c(struct bq27x00_device_info *di, u8 reg,
+ u16 val, bool single)
+{
+ struct i2c_client *client = to_i2c_client(di->dev);
+ unsigned char i2c_data[3];
+ int ret, len;
+
+ i2c_data[0] = reg;
+ i2c_data[1] = val & 0xff;
+
+ if (single) {
+ len = 2;
+ } else {
+ i2c_data[2] = (val >> 8) & 0xff;
+ len = 3;
+ }
+
+ ret = i2c_master_send(client, i2c_data, len);
+ if (ret == len)
+ return 0;
+
+ return (ret < 0) ? ret : -EIO;
+}
+
+static int bq27x00_ctrl_read_i2c(struct bq27x00_device_info *di,
+ u8 ctrl_reg, u16 ctrl_func_reg)
+{
+ int ret = bq27x00_write(di, ctrl_reg, ctrl_func_reg, false);
+ if (ret < 0) {
+ dev_err(di->dev, "write failure\n");
+ return ret;
+ }
+
+ ret = bq27x00_read(di, ctrl_reg, false);
+ if (ret < 0) {
+ dev_err(di->dev, "read failure\n");
+ return ret;
+ }
+
+ return ret;
+}
+
static int bq27x00_battery_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -757,6 +819,8 @@ static int bq27x00_battery_probe(struct i2c_client *client,
di->chip = id->driver_data;
di->bat.name = name;
di->bus.read = &bq27x00_read_i2c;
+ di->bus.ctrl_read = &bq27x00_ctrl_read_i2c;
+ di->bus.write = &bq27x00_write_i2c;
i2c_set_clientdata(client, di);
@@ -767,7 +831,7 @@ static int bq27x00_battery_probe(struct i2c_client *client,
goto batt_failed_3;
}
- read_data = i2c_smbus_read_word_data(di->client, BQ27x00_REG_FLAGS);
+ read_data = bq27x00_read(di, BQ27x00_REG_FLAGS, false);
if (!(read_data & BQ27500_FLAG_BAT_DET)) {
dev_err(&client->dev, "no battery present\n");
@@ -814,24 +878,19 @@ static int bq27x00_battery_remove(struct i2c_client *client)
static int bq27x00_battery_suspend(struct i2c_client *client,
pm_message_t state)
{
- u8 ret;
- struct bq27x00_device_info *bq27500_device;
-
- bq27500_device = i2c_get_clientdata(client);
+ int ret;
+ struct bq27x00_device_info *di = i2c_get_clientdata(client);
- if (bq27500_device->chip == BQ27510) {
- ret = i2c_smbus_write_word_data(bq27500_device->client,
- BQ27510_CNTL, BQ27510_CNTL_SET_SLEEP);
+ if (di->chip == BQ27510) {
+ ret = bq27x00_write(di, BQ27510_CNTL,
+ BQ27510_CNTL_SET_SLEEP, false);
if (ret < 0) {
- dev_err(&bq27500_device->client->dev,
- "write failure\n");
+ dev_err(di->dev, "write failure\n");
return ret;
}
- ret = i2c_smbus_write_word_data(bq27500_device->client,
- BQ27510_CNTL, 0x01);
- if (ret < 0) {
- dev_err(&bq27500_device->client->dev,
- "write failure\n");
+ ret = bq27x00_write(di, BQ27510_CNTL, 0x01, false);
+ if (ret < 0) {
+ dev_err(di->dev, "write failure\n");
return ret;
}
}
@@ -840,24 +899,19 @@ static int bq27x00_battery_suspend(struct i2c_client *client,
static int bq27x00_battery_resume(struct i2c_client *client)
{
- u8 ret;
- struct bq27x00_device_info *bq27500_device;
-
- bq27500_device = i2c_get_clientdata(client);
+ int ret;
+ struct bq27x00_device_info *di = i2c_get_clientdata(client);
- if (bq27500_device->chip == BQ27510) {
- ret = i2c_smbus_write_word_data(bq27500_device->client,
- BQ27510_CNTL, BQ27510_CNTL_CLEAR_SLEEP);
+ if (di->chip == BQ27510) {
+ ret = bq27x00_write(di, BQ27510_CNTL,
+ BQ27510_CNTL_CLEAR_SLEEP, false);
if (ret < 0) {
- dev_err(&bq27500_device->client->dev,
- "write failure\n");
+ dev_err(di->dev, "write failure\n");
return ret;
}
- ret = i2c_smbus_write_word_data(bq27500_device->client,
- BQ27510_CNTL, 0x01);
- if (ret < 0) {
- dev_err(&bq27500_device->client->dev,
- "write failure\n");
+ ret = bq27x00_write(di, BQ27510_CNTL, 0x01, false);
+ if (ret < 0) {
+ dev_err(di->dev, "write failure\n");
return ret;
}
}