summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPritesh Raithatha <praithatha@nvidia.com>2011-08-23 22:23:59 +0530
committerRyan Wong <ryanw@nvidia.com>2011-08-24 17:12:28 -0700
commite70ba6bd3c7f3beaa106751d0e08069d713b31ef (patch)
tree5b9aee2e72ccb5b4af8da0bd27d7c642f65b8228
parent4080e9300e2dd2c75189de83923448108f40b009 (diff)
power: bq27x00: correct i2c function calls
For i2c transfer existing code using mix of i2c_smbus_read_word_data and i2c_transfer. As they both are not serialized, they both are independently accessing i2c bus. In a situation like power plug connect/disconnect while device in suspended state, they both are called parallelly and we are getting garbage data. Using only one function i2c_smbus_read_word_data at all place solves the issue. Bug 866179 Original author: Pritesh Raithatha Original change: http://git-master/r/#change,48739 Signed-off-by: Pritesh Raithatha <praithatha@nvidia.com> Change-Id: Ib5c4377742da3703d97cbbac234fb2fbf1f70999 Reviewed-on: http://git-master/r/48771 Tested-by: Daniel Solomon <daniels@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com> Reviewed-by: Ryan Wong <ryanw@nvidia.com> Tested-by: Ryan Wong <ryanw@nvidia.com>
-rw-r--r--drivers/power/bq27x00_battery.c180
1 files changed, 59 insertions, 121 deletions
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 144dbea01afd..fc21818f3b89 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -73,10 +73,6 @@ static DEFINE_IDR(battery_id);
static DEFINE_MUTEX(battery_mutex);
struct bq27x00_device_info;
-struct bq27x00_access_methods {
- int (*read)(u8 reg, int *rt_value, int b_single,
- struct bq27x00_device_info *di);
-};
enum bq27x00_chip { BQ27000, BQ27500, BQ27510 };
enum bq27x00_status { CHARGING, DISCHARGING };
@@ -84,7 +80,6 @@ enum bq27x00_status { CHARGING, DISCHARGING };
struct bq27x00_device_info {
struct device *dev;
int id;
- struct bq27x00_access_methods *bus;
struct power_supply bat;
struct power_supply ac;
struct timer_list battery_poll_timer;
@@ -116,16 +111,6 @@ static enum power_supply_property bq27x00_battery_props[] = {
POWER_SUPPLY_PROP_HEALTH,
};
-/*
- * Common code for BQ27x00 devices
- */
-
-static int bq27x00_read(u8 reg, int *rt_value, int b_single,
- struct bq27x00_device_info *di)
-{
- return di->bus->read(reg, rt_value, b_single, di);
-}
-
static int bq27510_battery_health(struct bq27x00_device_info *di,
int reg_offset)
{
@@ -134,7 +119,7 @@ static int bq27510_battery_health(struct bq27x00_device_info *di,
if (di->chip == BQ27500 || di->chip == BQ27510) {
ret = i2c_smbus_read_word_data(di->client, reg_offset);
- if (ret < 0) {
+ if (ret < 0) {
dev_err(di->dev, "read failure\n");
return ret;
}
@@ -158,18 +143,17 @@ static int bq27510_battery_health(struct bq27x00_device_info *di,
static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
{
int ret;
- int temp = 0;
- ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
- if (ret) {
+ ret = i2c_smbus_read_word_data(di->client, BQ27x00_REG_TEMP);
+ if (ret < 0) {
dev_err(di->dev, "error reading temperature\n");
return ret;
}
if ((di->chip == BQ27500) || (di->chip == BQ27510))
- return temp - 2731;
+ return ret - 2731;
else
- return ((temp >> 2) - 273) * 10;
+ return ((ret >> 2) - 273) * 10;
}
/*
@@ -179,15 +163,14 @@ static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
{
int ret;
- int volt = 0;
- ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
- if (ret) {
+ ret = i2c_smbus_read_word_data(di->client, BQ27x00_REG_VOLT);
+ if (ret < 0) {
dev_err(di->dev, "error reading voltage\n");
return ret;
}
- return volt * 1000;
+ return ret * 1000;
}
/*
@@ -199,24 +182,27 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di)
{
int ret;
int curr = 0;
- int flags = 0;
- ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
- if (ret) {
+ ret = i2c_smbus_read_word_data(di->client, BQ27x00_REG_AI);
+ if (ret < 0) {
dev_err(di->dev, "error reading current\n");
return 0;
}
if ((di->chip == BQ27500) || (di->chip == BQ27510)) {
/* bq27500 returns signed value */
- curr = (int)(s16)curr;
+ curr = (int)(s16)ret;
} else {
- ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
+ curr = ret;
+
+ ret = i2c_smbus_read_word_data(di->client,
+ BQ27x00_REG_FLAGS);
if (ret < 0) {
dev_err(di->dev, "error reading flags\n");
return 0;
}
- if (flags & BQ27000_FLAG_CHGS) {
+
+ if (ret & BQ27000_FLAG_CHGS) {
dev_dbg(di->dev, "negative current!\n");
curr = -curr;
}
@@ -232,35 +218,36 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di)
static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
{
int ret;
- int rsoc = 0;
if ((di->chip == BQ27500) || (di->chip == BQ27510))
- ret = bq27x00_read(BQ27500_REG_SOC, &rsoc, 0, di);
+ ret = i2c_smbus_read_word_data(di->client,
+ BQ27500_REG_SOC);
else
- ret = bq27x00_read(BQ27000_REG_RSOC, &rsoc, 1, di);
- if (ret) {
+ ret = i2c_smbus_read_byte_data(di->client,
+ BQ27000_REG_RSOC);
+
+ if (ret < 0) {
dev_err(di->dev, "error reading relative State-of-Charge\n");
return ret;
}
- return rsoc;
+ return ret;
}
static int bq27x00_battery_status(struct bq27x00_device_info *di,
union power_supply_propval *val)
{
- int flags = 0;
int status;
int ret;
- ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
+ ret = i2c_smbus_read_word_data(di->client, BQ27x00_REG_FLAGS);
if (ret < 0) {
dev_err(di->dev, "error reading flags\n");
return ret;
}
if ((di->chip == BQ27500) || (di->chip == BQ27510)) {
- if (flags & BQ27500_FLAG_DSC) {
+ if (ret & BQ27500_FLAG_DSC) {
status = POWER_SUPPLY_STATUS_DISCHARGING;
if (di->battery_status != DISCHARGING) {
di->battery_status = DISCHARGING;
@@ -273,10 +260,10 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di,
di->battery_status_changed = false;
}
}
- if (flags & BQ27500_FLAG_FC)
+ if (ret & BQ27500_FLAG_FC)
status = POWER_SUPPLY_STATUS_FULL;
} else {
- if (flags & BQ27000_FLAG_CHGS)
+ if (ret & BQ27000_FLAG_CHGS)
status = POWER_SUPPLY_STATUS_CHARGING;
else
status = POWER_SUPPLY_STATUS_DISCHARGING;
@@ -293,19 +280,19 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di,
static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg,
union power_supply_propval *val)
{
- int tval = 0;
int ret;
- ret = bq27x00_read(reg, &tval, 0, di);
- if (ret) {
+ ret = i2c_smbus_read_word_data(di->client, reg);
+ if (ret < 0) {
dev_err(di->dev, "error reading register %02x\n", reg);
return ret;
}
- if (tval == 65535)
+ if (ret == 65535)
return -ENODATA;
- val->intval = tval * 60;
+ val->intval = ret * 60;
+
return 0;
}
@@ -315,28 +302,36 @@ 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
+ if (ret < 0) {
+ dev_err(di->dev, "error reading flags\n");
+ return ret;
+ }
+
+ if (ret & BQ27500_FLAG_BAT_DET)
val->intval = 1;
+ else
+ val->intval = 0;
+
return val->intval;
}
static char bq27510_serial[5];
-static int bq27510_get_battery_serial_number(struct bq27x00_device_info *di,
- union power_supply_propval *val)
+static int bq27510_get_battery_serial_number(
+ struct bq27x00_device_info *di,
+ union power_supply_propval *val)
{
int ret;
if (di->chip == BQ27510) {
- ret = i2c_smbus_write_word_data(di->client, BQ27510_CNTL,
+ ret = i2c_smbus_write_word_data(di->client,
+ 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) {
+ if (ret < 0) {
dev_err(di->dev, "read failure\n");
return ret;
}
@@ -361,7 +356,7 @@ static int bq27510_battery_energy_now(struct bq27x00_device_info *di,
if (di->chip == BQ27510) {
ret = i2c_smbus_read_word_data(di->client, reg_offset);
- if (ret < 0) {
+ if (ret < 0) {
dev_err(di->dev, "read failure\n");
return ret;
}
@@ -387,7 +382,7 @@ static int bq27510_battery_cycle_count(struct bq27x00_device_info *di,
if (di->chip == BQ27510) {
ret = i2c_smbus_read_word_data(di->client, reg_offset);
- if (ret < 0)
+ if (ret < 0)
dev_err(di->dev, "read failure\n");
return ret;
} else {
@@ -518,49 +513,6 @@ static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
di->ac.get_property = bq27x00_ac_get_property;
}
-/*
- * i2c specific code
- */
-
-static int bq27x00_read_i2c(u8 reg, int *rt_value, int b_single,
- struct bq27x00_device_info *di)
-{
- struct i2c_client *client = di->client;
- struct i2c_msg msg[1];
- unsigned char data[2];
- int err;
-
- if (!client->adapter)
- return -ENODEV;
-
- msg->addr = client->addr;
- msg->flags = 0;
- msg->len = 1;
- msg->buf = data;
-
- data[0] = reg;
- err = i2c_transfer(client->adapter, msg, 1);
-
- if (err >= 0) {
- if (!b_single)
- msg->len = 2;
- else
- msg->len = 1;
-
- msg->flags = I2C_M_RD;
- err = i2c_transfer(client->adapter, msg, 1);
- if (err >= 0) {
- if (!b_single)
- *rt_value = get_unaligned_le16(data);
- else
- *rt_value = data[0];
-
- return 0;
- }
- }
- return err;
-}
-
static irqreturn_t ac_present_irq(int irq, void *data)
{
struct bq27x00_device_info *di = data;
@@ -598,7 +550,6 @@ static int bq27x00_battery_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct bq27x00_device_info *di;
- struct bq27x00_access_methods *bus;
int num;
u16 read_data;
int retval = 0;
@@ -625,14 +576,6 @@ static int bq27x00_battery_probe(struct i2c_client *client,
di->battery_status_changed = false;
di->battery_status = DISCHARGING;
- bus = kzalloc(sizeof(*bus), GFP_KERNEL);
- if (!bus) {
- dev_err(&client->dev, "failed to allocate access method "
- "data\n");
- retval = -ENOMEM;
- goto batt_failed_2;
- }
-
di->irq = client->irq;
if (client->dev.platform_data) {
di->plat_data = kzalloc(sizeof(struct bq27x00_platform_data),
@@ -641,7 +584,7 @@ static int bq27x00_battery_probe(struct i2c_client *client,
dev_err(&client->dev,
"failed to allocate platform data\n");
retval = -ENOMEM;
- goto batt_failed_3;
+ goto batt_failed_2;
}
memcpy(di->plat_data, client->dev.platform_data,
sizeof(struct bq27x00_platform_data));
@@ -649,8 +592,6 @@ static int bq27x00_battery_probe(struct i2c_client *client,
i2c_set_clientdata(client, di);
di->dev = &client->dev;
- bus->read = &bq27x00_read_i2c;
- di->bus = bus;
di->client = client;
/* Let's see whether this adapter can support what we need. */
@@ -673,7 +614,7 @@ static int bq27x00_battery_probe(struct i2c_client *client,
retval = power_supply_register(&client->dev, &di->bat);
if (retval) {
dev_err(&client->dev, "failed to register battery\n");
- goto batt_failed_4;
+ goto batt_failed_3;
}
setup_timer(&di->battery_poll_timer,
@@ -685,7 +626,7 @@ static int bq27x00_battery_probe(struct i2c_client *client,
retval = power_supply_register(&client->dev, &di->ac);
if (retval) {
dev_err(&client->dev, "failed to register ac power supply\n");
- goto batt_failed_5;
+ goto batt_failed_4;
}
retval = request_threaded_irq(di->irq, NULL,
@@ -695,23 +636,21 @@ static int bq27x00_battery_probe(struct i2c_client *client,
if (retval < 0) {
dev_err(&di->client->dev,
"%s: request_irq failed(%d)\n", __func__, retval);
- goto batt_failed_6;
+ goto batt_failed_5;
}
dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
return 0;
-batt_failed_6:
- power_supply_unregister(&di->ac);
batt_failed_5:
+ power_supply_unregister(&di->ac);
+batt_failed_4:
if (di->battery_present) {
power_supply_unregister(&di->bat);
del_timer_sync(&di->battery_poll_timer);
}
-batt_failed_4:
- kfree(di->plat_data);
batt_failed_3:
- kfree(bus);
+ kfree(di->plat_data);
batt_failed_2:
kfree(di);
batt_failed_1:
@@ -739,7 +678,6 @@ static int bq27x00_battery_remove(struct i2c_client *client)
mutex_unlock(&battery_mutex);
kfree(di->plat_data);
- kfree(di->bus);
kfree(di);
return 0;
@@ -769,7 +707,7 @@ static int bq27x00_battery_suspend(struct i2c_client *client,
}
ret = i2c_smbus_write_word_data(bq27500_device->client,
BQ27510_CNTL, BQ27510_CNTL_DEVICE_TYPE);
- if (ret < 0) {
+ if (ret < 0) {
dev_err(&bq27500_device->client->dev,
"write failure\n");
return ret;
@@ -798,7 +736,7 @@ static int bq27x00_battery_resume(struct i2c_client *client)
}
ret = i2c_smbus_write_word_data(bq27500_device->client,
BQ27510_CNTL, BQ27510_CNTL_DEVICE_TYPE);
- if (ret < 0) {
+ if (ret < 0) {
dev_err(&bq27500_device->client->dev,
"write failure\n");
return ret;