You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
280 lines
8.9 KiB
280 lines
8.9 KiB
From 46159c9a3fba291d106625092fd62358548894e0 Mon Sep 17 00:00:00 2001
|
|
From: Andy Green <andy@openmoko.com>
|
|
Date: Tue, 22 Jul 2008 13:16:16 +0100
|
|
Subject: [PATCH] fix-bq27000-charger-state-tracking.patch
|
|
|
|
Charger trigger stuff goes and asks for POWER_SUPPLY_PROP_STATUS
|
|
to figure out what the charger state is. But until now, we only
|
|
reported there what we found out from HDQ, and the HDQ registers
|
|
are not updated very often in the coulomb counter, it can be 4
|
|
or more second lag before it tells us about what it experiences.
|
|
|
|
When we react to USB insertion and only after 500ms debounce tell
|
|
power_supply stuff that something changed, it most times will
|
|
see old pre-USB-insertion state from bq27000 over HDQ at that time
|
|
and will report it ain't charging, buggering up the LED trigger
|
|
tracking.
|
|
|
|
This patch maintains distance between bq27000 and pcf50633 by
|
|
having platform callbacks in bq27000 that it can use to ask about
|
|
definitive charger "online" presence and "activity", whether the
|
|
charger says it is charging. If these callbacks are implemented
|
|
(and we implement them in this patch up in mach_gta02.c) then
|
|
this information is used in preference to what is found from
|
|
HDQ.
|
|
|
|
Result is if you set the LED trigger like this:
|
|
|
|
echo bat-charging > /sys/devices/platform/gta02-led.0/leds/gta02-aux:red/trigger
|
|
|
|
then it lights up properly on USB insertion now, goes away on
|
|
removal properly, as as far as I saw, when charging stops too.
|
|
|
|
Signed-off-by: Andy Green <andy@openmoko.com>
|
|
---
|
|
arch/arm/mach-s3c2440/mach-gta02.c | 32 +++++++++++++++--
|
|
drivers/power/bq27000_battery.c | 65 ++++++++++++++++++++++++-----------
|
|
include/linux/bq27000_battery.h | 2 +
|
|
3 files changed, 74 insertions(+), 25 deletions(-)
|
|
|
|
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
|
|
index 59ba890..1fcd3fd 100644
|
|
--- a/arch/arm/mach-s3c2440/mach-gta02.c
|
|
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
|
|
@@ -96,6 +96,9 @@ struct resume_dependency resume_dep_jbt_glamo;
|
|
struct resume_dependency resume_dep_glamo_mci_pcf;
|
|
|
|
|
|
+static int gta02_charger_online_status;
|
|
+static int gta02_charger_active_status;
|
|
+
|
|
/* define FIQ IPC struct */
|
|
/*
|
|
* contains stuff FIQ ISR modifies and normal kernel code can see and use
|
|
@@ -457,12 +460,25 @@ static struct s3c2410_uartcfg gta02_uartcfgs[] = {
|
|
|
|
/* BQ27000 Battery */
|
|
|
|
+static int gta02_get_charger_online_status(void)
|
|
+{
|
|
+ return gta02_charger_online_status;
|
|
+}
|
|
+
|
|
+static int gta02_get_charger_active_status(void)
|
|
+{
|
|
+ return gta02_charger_active_status;
|
|
+}
|
|
+
|
|
+
|
|
struct bq27000_platform_data bq27000_pdata = {
|
|
.name = "bat",
|
|
.rsense_mohms = 20,
|
|
.hdq_read = gta02hdq_read,
|
|
.hdq_write = gta02hdq_write,
|
|
.hdq_initialized = gta02hdq_initialized,
|
|
+ .get_charger_online_status = gta02_get_charger_online_status,
|
|
+ .get_charger_active_status = gta02_get_charger_active_status
|
|
};
|
|
|
|
struct platform_device bq27000_battery_device = {
|
|
@@ -481,12 +497,20 @@ static int pmu_callback(struct device *dev, unsigned int feature,
|
|
switch (feature) {
|
|
case PCF50633_FEAT_MBC:
|
|
switch (event) {
|
|
- case PMU_EVT_USB_INSERT:
|
|
- case PMU_EVT_USB_REMOVE:
|
|
case PMU_EVT_CHARGER_IDLE:
|
|
+ gta02_charger_active_status = 0;
|
|
+ break;
|
|
case PMU_EVT_CHARGER_ACTIVE:
|
|
- case PMU_EVT_INSERT: /* adapter */
|
|
- case PMU_EVT_REMOVE: /* adapter */
|
|
+ gta02_charger_active_status = 1;
|
|
+ break;
|
|
+ case PMU_EVT_USB_INSERT:
|
|
+ gta02_charger_online_status = 1;
|
|
+ break;
|
|
+ case PMU_EVT_USB_REMOVE:
|
|
+ gta02_charger_online_status = 0;
|
|
+ break;
|
|
+ case PMU_EVT_INSERT: /* adapter is unsused */
|
|
+ case PMU_EVT_REMOVE: /* adapter is unused */
|
|
break;
|
|
default:
|
|
break;
|
|
diff --git a/drivers/power/bq27000_battery.c b/drivers/power/bq27000_battery.c
|
|
index 4855d5a..7020608 100644
|
|
--- a/drivers/power/bq27000_battery.c
|
|
+++ b/drivers/power/bq27000_battery.c
|
|
@@ -113,12 +113,7 @@ enum bq27000_status_flags {
|
|
struct bq27000_device_info {
|
|
struct device *dev;
|
|
struct power_supply bat;
|
|
-
|
|
- int rsense_mohms; /* from platform */
|
|
-
|
|
- int (*hdq_initialized)(void); /* from platform */
|
|
- int (*hdq_read)(int); /* from platform */
|
|
- int (*hdq_write)(int, u8); /* from platform */
|
|
+ struct bq27000_platform_data *pdata;
|
|
};
|
|
|
|
/*
|
|
@@ -136,16 +131,16 @@ static int hdq_read16(struct bq27000_device_info *di, int address)
|
|
|
|
while (retries--) {
|
|
|
|
- high = (di->hdq_read)(address + 1); /* high part */
|
|
+ high = (di->pdata->hdq_read)(address + 1); /* high part */
|
|
|
|
if (high < 0)
|
|
return high;
|
|
- acc = (di->hdq_read)(address);
|
|
+ acc = (di->pdata->hdq_read)(address);
|
|
if (acc < 0)
|
|
return acc;
|
|
|
|
/* confirm high didn't change between reading it and low */
|
|
- if (high == (di->hdq_read)(address + 1))
|
|
+ if (high == (di->pdata->hdq_read)(address + 1))
|
|
return (high << 8) | acc;
|
|
}
|
|
|
|
@@ -170,12 +165,36 @@ static int bq27000_battery_get_property(struct power_supply *psy,
|
|
int v, n;
|
|
struct bq27000_device_info *di = to_bq27000_device_info(psy);
|
|
|
|
- if (!(di->hdq_initialized)())
|
|
+ if (!(di->pdata->hdq_initialized)())
|
|
return -EINVAL;
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_STATUS:
|
|
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
|
|
+
|
|
+ if (!di->pdata->get_charger_online_status)
|
|
+ goto use_bat;
|
|
+ if ((di->pdata->get_charger_online_status)()) {
|
|
+ /*
|
|
+ * charger is definitively present
|
|
+ * we report our state in terms of what it says it
|
|
+ * is doing
|
|
+ */
|
|
+ if (!di->pdata->get_charger_active_status)
|
|
+ goto use_bat;
|
|
+ if ((di->pdata->get_charger_active_status)())
|
|
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
|
+ else
|
|
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
|
+ break;
|
|
+ }
|
|
+use_bat:
|
|
+ /*
|
|
+ * either the charger is not connected, or the
|
|
+ * platform doesn't give info about charger, use battery state
|
|
+ * but... battery state can be out of date by 4 seconds or
|
|
+ * so... use the platform callbacks if possible.
|
|
+ */
|
|
v = hdq_read16(di, BQ27000_AI_L);
|
|
if (v < 0)
|
|
return v;
|
|
@@ -189,7 +208,7 @@ static int bq27000_battery_get_property(struct power_supply *psy,
|
|
break;
|
|
}
|
|
/* power is actually going in or out... */
|
|
- v = (di->hdq_read)(BQ27000_FLAGS);
|
|
+ v = (di->pdata->hdq_read)(BQ27000_FLAGS);
|
|
if (v < 0)
|
|
return v;
|
|
if (v & BQ27000_STATUS_CHGS)
|
|
@@ -205,7 +224,7 @@ static int bq27000_battery_get_property(struct power_supply *psy,
|
|
val->intval = v * 1000;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
|
- v = (di->hdq_read)(BQ27000_FLAGS);
|
|
+ v = (di->pdata->hdq_read)(BQ27000_FLAGS);
|
|
if (v < 0)
|
|
return v;
|
|
if (v & BQ27000_STATUS_CHGS)
|
|
@@ -215,13 +234,13 @@ static int bq27000_battery_get_property(struct power_supply *psy,
|
|
v = hdq_read16(di, BQ27000_AI_L);
|
|
if (v < 0)
|
|
return v;
|
|
- val->intval = (v * n) / di->rsense_mohms;
|
|
+ val->intval = (v * n) / di->pdata->rsense_mohms;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHARGE_FULL:
|
|
v = hdq_read16(di, BQ27000_LMD_L);
|
|
if (v < 0)
|
|
return v;
|
|
- val->intval = (v * 3570) / di->rsense_mohms;
|
|
+ val->intval = (v * 3570) / di->pdata->rsense_mohms;
|
|
break;
|
|
case POWER_SUPPLY_PROP_TEMP:
|
|
v = hdq_read16(di, BQ27000_TEMP_L);
|
|
@@ -235,12 +254,12 @@ static int bq27000_battery_get_property(struct power_supply *psy,
|
|
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CAPACITY:
|
|
- val->intval = (di->hdq_read)(BQ27000_RSOC);
|
|
+ val->intval = (di->pdata->hdq_read)(BQ27000_RSOC);
|
|
if (val->intval < 0)
|
|
return val->intval;
|
|
break;
|
|
case POWER_SUPPLY_PROP_PRESENT:
|
|
- v = (di->hdq_read)(BQ27000_RSOC);
|
|
+ v = (di->pdata->hdq_read)(BQ27000_RSOC);
|
|
val->intval = !(v < 0);
|
|
break;
|
|
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
|
|
@@ -255,6 +274,12 @@ static int bq27000_battery_get_property(struct power_supply *psy,
|
|
return v;
|
|
val->intval = 60 * v;
|
|
break;
|
|
+ case POWER_SUPPLY_PROP_ONLINE:
|
|
+ if (di->pdata->get_charger_online_status)
|
|
+ val->intval = (di->pdata->get_charger_online_status)();
|
|
+ else
|
|
+ return -EINVAL;
|
|
+ break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
@@ -272,7 +297,8 @@ static enum power_supply_property bq27000_battery_props[] = {
|
|
POWER_SUPPLY_PROP_PRESENT,
|
|
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
|
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
|
|
- POWER_SUPPLY_PROP_CAPACITY
|
|
+ POWER_SUPPLY_PROP_CAPACITY,
|
|
+ POWER_SUPPLY_PROP_ONLINE
|
|
};
|
|
|
|
static int bq27000_battery_probe(struct platform_device *pdev)
|
|
@@ -302,10 +328,7 @@ static int bq27000_battery_probe(struct platform_device *pdev)
|
|
di->bat.external_power_changed =
|
|
bq27000_battery_external_power_changed;
|
|
di->bat.use_for_apm = 1;
|
|
- 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->pdata = pdata;
|
|
|
|
retval = power_supply_register(&pdev->dev, &di->bat);
|
|
if (retval) {
|
|
diff --git a/include/linux/bq27000_battery.h b/include/linux/bq27000_battery.h
|
|
index fed4287..a617466 100644
|
|
--- a/include/linux/bq27000_battery.h
|
|
+++ b/include/linux/bq27000_battery.h
|
|
@@ -9,6 +9,8 @@ struct bq27000_platform_data {
|
|
int (*hdq_read)(int);
|
|
int (*hdq_write)(int, u8);
|
|
int (*hdq_initialized)(void);
|
|
+ int (*get_charger_online_status)(void);
|
|
+ int (*get_charger_active_status)(void);
|
|
};
|
|
|
|
#endif
|
|
--
|
|
1.5.6.5
|
|
|
|
|