aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Fertser <fercerpav@gmail.com>2009-07-26 18:00:29 +0400
committerPaul Fertser <fercerpav@gmail.com>2009-08-02 11:24:27 +0400
commitec22388dfefaf8eda07d12284b8f946d3c6eb148 (patch)
treec6a90296ffceca203058c883d85d111af10e0f4d
parent5af71f726c58adeef22afafacc2242fd920f9882 (diff)
gta01_battery: generalise the driver, add capacity estimation
Check if machine-specific hooks exist before calling, this allows to use this driver with gta02 or any other device that is able to provide battery voltage readings. Report an estimate of capacity percentage left, based on discharge curves. Strictly speaking, this is a violation of power_supply class specs but since this is the only driver for dumb batteries and userspace lacks any library to do the estimation itself, we have to stuff it here. Please keep in mind that this estimation is by no means accurate, usually cell phones have only 5 bars to represent charge status. Credit goes to Joerg Reisenweber and SpeedEvil for helping with gathering and analysing the data. Signed-off-by: Paul Fertser <fercerpav@gmail.com>
-rw-r--r--drivers/power/gta01_battery.c54
1 files changed, 49 insertions, 5 deletions
diff --git a/drivers/power/gta01_battery.c b/drivers/power/gta01_battery.c
index 5b1a6c9b966..3c7c49777b0 100644
--- a/drivers/power/gta01_battery.c
+++ b/drivers/power/gta01_battery.c
@@ -23,8 +23,35 @@ static enum power_supply_property gta01_bat_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
};
+static int gta01_bat_voltscale(int volt)
+{
+ /* This table is suggested by SpeedEvil based on analysis of
+ * experimental data */
+ static const int lut[][2] = {
+ { 4120, 100 },
+ { 3900, 60 },
+ { 3740, 25 },
+ { 3600, 5 },
+ { 3000, 0 } };
+ int i, res = 0;
+
+ if (volt > lut[0][0])
+ res = lut[0][1];
+ else
+ for (i = 0; lut[i][1]; i++) {
+ if (volt <= lut[i][0] && volt >= lut[i+1][0]) {
+ res = lut[i][1] - (lut[i][0]-volt)*
+ (lut[i][1]-lut[i+1][1])/
+ (lut[i][0]-lut[i+1][0]);
+ break;
+ }
+ }
+ return res;
+}
+
static int gta01_bat_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -33,20 +60,37 @@ static int gta01_bat_get_property(struct power_supply *psy,
switch(psp) {
case POWER_SUPPLY_PROP_STATUS:
- if (bat->pdata->get_charging_status())
- val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ if (bat->pdata->get_charging_status)
+ if (bat->pdata->get_charging_status())
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
else
- val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- val->intval = bat->pdata->get_voltage();
+ if (bat->pdata->get_voltage)
+ val->intval = bat->pdata->get_voltage();
+ else
+ val->intval = 0;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
- val->intval = bat->pdata->get_current();
+ if (bat->pdata->get_current)
+ val->intval = bat->pdata->get_current();
+ else
+ val->intval = 0;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = 1; /* You must never run GTA01 without battery. */
break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ if (bat->pdata->get_voltage)
+ val->intval = gta01_bat_voltscale(
+ bat->pdata->get_voltage()/1000);
+ else
+ val->intval = 0;
+ break;
+
default:
return -EINVAL;
}