Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 217403
b: refs/heads/master
c: d3ab61e
h: refs/heads/master
i:
  217401: 30e3a0f
  217399: a2802ce
v: v3
  • Loading branch information
Rhyland Klein authored and Anton Vorontsov committed Sep 28, 2010
1 parent 95332da commit 28688d6
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 49 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9c99f08991b38bf6ab62ffe9013ee46ff41d66d0
refs/heads/master: d3ab61ecbab2b8950108b3541bc9eda515d605e0
204 changes: 156 additions & 48 deletions trunk/drivers/power/bq20z75.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,19 @@ enum {
REG_TIME_TO_FULL,
REG_STATUS,
REG_CYCLE_COUNT,
REG_SERIAL_NUMBER
REG_SERIAL_NUMBER,
REG_REMAINING_CAPACITY,
REG_FULL_CHARGE_CAPACITY,
REG_DESIGN_CAPACITY,
REG_DESIGN_VOLTAGE,
};

/* manufacturer access defines */
#define MANUFACTURER_ACCESS_STATUS 0x0006
#define MANUFACTURER_ACCESS_SLEEP 0x0011

/* battery status value bits */
#define BATTERY_CHARGING 0x40
#define BATTERY_DISCHARGING 0x40
#define BATTERY_FULL_CHARGED 0x20
#define BATTERY_FULL_DISCHARGED 0x10

Expand Down Expand Up @@ -72,6 +76,10 @@ static const struct bq20z75_device_data {
32767),
[REG_CAPACITY] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
[REG_REMAINING_CAPACITY] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
[REG_FULL_CHARGE_CAPACITY] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
[REG_TIME_TO_EMPTY] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0,
65535),
Expand All @@ -82,6 +90,12 @@ static const struct bq20z75_device_data {
BQ20Z75_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535),
[REG_CYCLE_COUNT] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535),
[REG_DESIGN_CAPACITY] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0,
65535),
[REG_DESIGN_VOLTAGE] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0,
65535),
[REG_SERIAL_NUMBER] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535),
};
Expand All @@ -99,13 +113,46 @@ static enum power_supply_property bq20z75_properties[] = {
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_ENERGY_FULL,
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
};

struct bq20z75_info {
struct i2c_client *client;
struct power_supply power_supply;
};

static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
{
s32 ret;

ret = i2c_smbus_read_word_data(client, address);
if (ret < 0) {
dev_err(&client->dev,
"%s: i2c read at address 0x%x failed\n",
__func__, address);
return ret;
}
return le16_to_cpu(ret);
}

static int bq20z75_write_word_data(struct i2c_client *client, u8 address,
u16 value)
{
s32 ret;

ret = i2c_smbus_write_word_data(client, address, le16_to_cpu(value));
if (ret < 0) {
dev_err(&client->dev,
"%s: i2c write to address 0x%x failed\n",
__func__, address);
return ret;
}
return 0;
}

static int bq20z75_get_battery_presence_and_health(
struct i2c_client *client, enum power_supply_property psp,
union power_supply_propval *val)
Expand All @@ -115,24 +162,17 @@ static int bq20z75_get_battery_presence_and_health(
/* Write to ManufacturerAccess with
* ManufacturerAccess command and then
* read the status */
ret = i2c_smbus_write_word_data(client,
ret = bq20z75_write_word_data(client,
bq20z75_data[REG_MANUFACTURER_DATA].addr,
MANUFACTURER_ACCESS_STATUS);
if (ret < 0) {
dev_err(&client->dev,
"%s: i2c write for battery presence failed\n",
__func__);
return -ENODEV;
}
if (ret < 0)
return ret;

ret = i2c_smbus_read_word_data(client,

ret = bq20z75_read_word_data(client,
bq20z75_data[REG_MANUFACTURER_DATA].addr);
if (ret < 0) {
dev_err(&client->dev,
"%s: i2c read for battery presence failed\n",
__func__);
return -EIO;
}
if (ret < 0)
return ret;

if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value ||
ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) {
Expand Down Expand Up @@ -171,31 +211,28 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
{
s32 ret;

ret = i2c_smbus_read_word_data(client,
ret = bq20z75_read_word_data(client,
bq20z75_data[reg_offset].addr);
if (ret < 0) {
dev_err(&client->dev,
"%s: i2c read for %d failed\n", __func__, reg_offset);
return -EIO;
}
if (ret < 0)
return ret;

/* returned values are 16 bit */
if (bq20z75_data[reg_offset].min_value < 0)
ret = (s16)ret;

if (ret >= bq20z75_data[reg_offset].min_value &&
ret <= bq20z75_data[reg_offset].max_value) {
val->intval = ret;
if (psp == POWER_SUPPLY_PROP_STATUS) {
if (ret & BATTERY_CHARGING)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (ret & BATTERY_FULL_CHARGED)
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
else if (ret & BATTERY_DISCHARGING)
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
else
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)
val->intval = ret - 2731;
} else {
if (psp == POWER_SUPPLY_PROP_STATUS)
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
Expand All @@ -206,21 +243,77 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
return 0;
}

static void bq20z75_unit_adjustment(struct i2c_client *client,
enum power_supply_property psp, union power_supply_propval *val)
{
#define BASE_UNIT_CONVERSION 1000
#define BATTERY_MODE_CAP_MULT_WATT (10 * BASE_UNIT_CONVERSION)
#define TIME_UNIT_CONVERSION 600
#define TEMP_KELVIN_TO_CELCIUS 2731
switch (psp) {
case POWER_SUPPLY_PROP_ENERGY_NOW:
case POWER_SUPPLY_PROP_ENERGY_FULL:
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
val->intval *= BATTERY_MODE_CAP_MULT_WATT;
break;

case POWER_SUPPLY_PROP_VOLTAGE_NOW:
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval *= BASE_UNIT_CONVERSION;
break;

case POWER_SUPPLY_PROP_TEMP:
/* bq20z75 provides battery tempreture in 0.1°K
* so convert it to 0.1°C */
val->intval -= TEMP_KELVIN_TO_CELCIUS;
val->intval *= 10;
break;

case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
val->intval *= TIME_UNIT_CONVERSION;
break;

default:
dev_dbg(&client->dev,
"%s: no need for unit conversion %d\n", __func__, psp);
}
}

static int bq20z75_get_battery_capacity(struct i2c_client *client,
int reg_offset, enum power_supply_property psp,
union power_supply_propval *val)
{
s32 ret;

ret = i2c_smbus_read_byte_data(client, bq20z75_data[REG_CAPACITY].addr);
if (ret < 0) {
dev_err(&client->dev,
"%s: i2c read for %d failed\n", __func__, REG_CAPACITY);
return -EIO;
}
ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr);
if (ret < 0)
return ret;

/* bq20z75 spec says that this can be >100 %
* even if max value is 100 % */
val->intval = min(ret, 100);
if (psp == POWER_SUPPLY_PROP_CAPACITY) {
/* bq20z75 spec says that this can be >100 %
* even if max value is 100 % */
val->intval = min(ret, 100);
} else
val->intval = ret;

return 0;
}

static char bq20z75_serial[5];
static int bq20z75_get_battery_serial_number(struct i2c_client *client,
union power_supply_propval *val)
{
int ret;

ret = bq20z75_read_word_data(client,
bq20z75_data[REG_SERIAL_NUMBER].addr);
if (ret < 0)
return ret;

ret = sprintf(bq20z75_serial, "%04x", ret);
val->strval = bq20z75_serial;

return 0;
}
Expand All @@ -247,8 +340,23 @@ static int bq20z75_get_property(struct power_supply *psy,
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;

case POWER_SUPPLY_PROP_ENERGY_NOW:
case POWER_SUPPLY_PROP_ENERGY_FULL:
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
case POWER_SUPPLY_PROP_CAPACITY:
ret = bq20z75_get_battery_capacity(client, val);
for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
if (psp == bq20z75_data[count].psp)
break;
}

ret = bq20z75_get_battery_capacity(client, count, psp, val);
if (ret)
return ret;

break;

case POWER_SUPPLY_PROP_SERIAL_NUMBER:
ret = bq20z75_get_battery_serial_number(client, val);
if (ret)
return ret;
break;
Expand All @@ -260,7 +368,7 @@ static int bq20z75_get_property(struct power_supply *psy,
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:
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
if (psp == bq20z75_data[count].psp)
break;
Expand All @@ -269,6 +377,7 @@ static int bq20z75_get_property(struct power_supply *psy,
ret = bq20z75_get_battery_property(client, count, psp, val);
if (ret)
return ret;

break;

default:
Expand All @@ -277,6 +386,9 @@ static int bq20z75_get_property(struct power_supply *psy,
return -EINVAL;
}

/* Convert units to match requirements for power supply class */
bq20z75_unit_adjustment(client, psp, val);

dev_dbg(&client->dev,
"%s: property = %d, value = %d\n", __func__, psp, val->intval);

Expand Down Expand Up @@ -335,15 +447,11 @@ static int bq20z75_suspend(struct i2c_client *client,
s32 ret;

/* write to manufacturer access with sleep command */
ret = i2c_smbus_write_word_data(client,
ret = bq20z75_write_word_data(client,
bq20z75_data[REG_MANUFACTURER_DATA].addr,
MANUFACTURER_ACCESS_SLEEP);
if (ret < 0) {
dev_err(&client->dev,
"%s: i2c write for %d failed\n",
__func__, MANUFACTURER_ACCESS_SLEEP);
return -EIO;
}
if (ret < 0)
return ret;

return 0;
}
Expand Down

0 comments on commit 28688d6

Please sign in to comment.