Attached is a patch to add:

Battery health
USB and AC power indicators
Change to threshold for detecting charge status

The last item is problematical for me. The battery tends to hover at 11 for BQ27000_AI_L and BQ27000_TTF_L is not zero. This is with 2 usb connections - one direct, 1 via debug board - directly into laptop. My blackberry complains it doesn't get enough juice under linux, so maybe that is the issue. Capacity on the battery is at 100%, though.

Sean

diff --git a/drivers/power/bq27000_battery.c b/drivers/power/bq27000_battery.c
index d19186a..17a8dcf 100644
--- a/drivers/power/bq27000_battery.c
+++ b/drivers/power/bq27000_battery.c
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/bq27000_battery.h>
+#include <linux/apm-emulation.h>
 
 enum bq27000_regs {
 	/* RAM regs */
@@ -110,9 +111,13 @@ enum bq27000_status_flags {
 
 #define NANOVOLTS_UNIT 3750
 
+#define BQ27000_ACTIVITY_THRESHOLD 12
+
 struct bq27000_device_info {
 	struct device *dev;
 	struct power_supply bat;
+	struct power_supply ac;
+	struct power_supply usb;
 
 	int rsense_mohms;		/* from platform */
 
@@ -152,13 +157,10 @@ static int hdq_read16(struct bq27000_device_info *di, int address)
 	return -ETIME;
 }
 
-#define to_bq27000_device_info(x) container_of((x), \
-					       struct bq27000_device_info, \
-					       bat);
-
 static void bq27000_battery_external_power_changed(struct power_supply *psy)
 {
-	struct bq27000_device_info *di = to_bq27000_device_info(psy);
+	struct bq27000_device_info *di = container_of(psy, struct bq27000_device_info, bat);
+
 
 	dev_dbg(di->dev, "%s\n", __FUNCTION__);
 }
@@ -168,7 +170,7 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 				       union power_supply_propval *val)
 {
 	int v, n;
-	struct bq27000_device_info *di = to_bq27000_device_info(psy);
+	struct bq27000_device_info *di = container_of(psy, struct bq27000_device_info, bat);
 
 	if (!(di->hdq_initialized)())
 		return -EINVAL;
@@ -179,7 +181,7 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 		v = hdq_read16(di, BQ27000_AI_L);
 		if (v < 0)
 			return v;
-		if (v < 2) { /* no real activity on the battery */
+		if (v < BQ27000_ACTIVITY_THRESHOLD) { /* no real activity on the battery */
 			if (!hdq_read16(di, BQ27000_TTF_L))
 				val->intval = POWER_SUPPLY_STATUS_FULL;
 			else
@@ -195,6 +197,15 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 		else
 			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
 		break;
+	case 	POWER_SUPPLY_PROP_HEALTH:
+		val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+		/* Do we have accurate readings... */
+		v = (di->hdq_read)(BQ27000_FLAGS);
+		if (v < 0)
+			return v;
+		if (v & BQ27000_STATUS_VDQ)
+			val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 		v = hdq_read16(di, BQ27000_VOLT_L);
 		if (v < 0)
@@ -252,6 +263,9 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 			return v;
 		val->intval = 60 * v;
 		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = "gta02";
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -259,8 +273,77 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 	return 0;
 }
 
+extern void (*apm_get_power_status)(struct apm_power_info *);
+
+static int ac_get_property(struct power_supply *psy,
+			enum power_supply_property psp,
+			union power_supply_propval *val)
+{
+	int ret = 0;
+	struct bq27000_device_info *di = container_of(psy, struct bq27000_device_info, ac);
+	struct apm_power_info info;
+
+	if (!(di->hdq_initialized)())
+		return -EINVAL;
+
+	apm_get_power_status (&info);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		switch (info.ac_line_status) {
+		case APM_AC_ONLINE:
+			val->intval = 1;
+			break;
+		case APM_AC_OFFLINE:
+			val->intval = 0;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int usb_get_property(struct power_supply *psy,
+			enum power_supply_property psp,
+			union power_supply_propval *val)
+{
+	int ret = 0;
+	struct bq27000_device_info *di = container_of(psy, struct bq27000_device_info, usb);
+	struct apm_power_info info;
+
+	if (!(di->hdq_initialized)())
+		return -EINVAL;
+
+	apm_get_power_status (&info);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		switch (info.ac_line_status) {
+		case APM_AC_ONLINE:
+			val->intval = 1;
+			break;
+		case APM_AC_OFFLINE:
+			val->intval = 0;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static enum power_supply_property bq27000_battery_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_CHARGE_FULL,
@@ -273,6 +356,10 @@ static enum power_supply_property bq27000_battery_props[] = {
 	POWER_SUPPLY_PROP_CAPACITY
 };
 
+static enum power_supply_property power_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
 static int bq27000_battery_probe(struct platform_device *pdev)
 {
 	int retval = 0;
@@ -292,17 +379,30 @@ static int bq27000_battery_probe(struct platform_device *pdev)
 	pdata = pdev->dev.platform_data;
 	di->dev		= &pdev->dev;
 	/* di->w1_dev	     = pdev->dev.parent; */
-	di->bat.name	   = pdata->name;
-	di->bat.type	   = POWER_SUPPLY_TYPE_BATTERY;
+	di->rsense_mohms    = pdata->rsense_mohms;
+	di->hdq_read        = pdata->hdq_read;
+	di->hdq_write       = pdata->hdq_write;
+	di->hdq_initialized = pdata->hdq_initialized;
+
+	di->bat.name	       = "battery";
+	di->bat.type	       = POWER_SUPPLY_TYPE_BATTERY;
 	di->bat.properties     = bq27000_battery_props;
 	di->bat.num_properties = ARRAY_SIZE(bq27000_battery_props);
 	di->bat.get_property   = bq27000_battery_get_property;
 	di->bat.external_power_changed =
 				  bq27000_battery_external_power_changed;
-	di->hdq_read = pdata->hdq_read;
-	di->hdq_write = pdata->hdq_write;
-	di->rsense_mohms = pdata->rsense_mohms;
-	di->hdq_initialized = pdata->hdq_initialized;
+
+	di->ac.name            = "ac";
+	di->ac.type            = POWER_SUPPLY_TYPE_MAINS;
+	di->ac.properties      = power_props;
+	di->ac.num_properties  = ARRAY_SIZE(power_props);
+	di->ac.get_property    = ac_get_property;
+
+	di->usb.name           = "usb";
+	di->usb.type           = POWER_SUPPLY_TYPE_USB;
+	di->usb.properties     = power_props;
+	di->usb.num_properties = ARRAY_SIZE(power_props);
+	di->usb.get_property   = usb_get_property;
 
 	retval = power_supply_register(&pdev->dev, &di->bat);
 	if (retval) {
@@ -310,8 +410,24 @@ static int bq27000_battery_probe(struct platform_device *pdev)
 		goto batt_failed;
 	}
 
+	retval = power_supply_register(&pdev->dev, &di->ac);
+	if (retval) {
+		dev_err(di->dev, "failed to register ac\n");
+		goto ac_failed;
+	}
+
+	retval = power_supply_register(&pdev->dev, &di->usb);
+	if (retval) {
+		dev_err(di->dev, "failed to register usb\n");
+		goto usb_failed;
+	}
+
 	return 0;
 
+usb_failed:
+	power_supply_unregister(&di->ac);
+ac_failed:
+	power_supply_unregister(&di->bat);
 batt_failed:
 	kfree(di);
 di_alloc_failed:
@@ -323,6 +439,8 @@ static int bq27000_battery_remove(struct platform_device *pdev)
 	struct bq27000_device_info *di = platform_get_drvdata(pdev);
 
 	power_supply_unregister(&di->bat);
+	power_supply_unregister(&di->ac);
+	power_supply_unregister(&di->usb);
 
 	return 0;
 }

Reply via email to