diff options
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.24/1242-fix-bq27000-charger-state-tracking.patch.patch')
-rw-r--r-- | target/linux/s3c24xx/patches-2.6.24/1242-fix-bq27000-charger-state-tracking.patch.patch | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.24/1242-fix-bq27000-charger-state-tracking.patch.patch b/target/linux/s3c24xx/patches-2.6.24/1242-fix-bq27000-charger-state-tracking.patch.patch new file mode 100644 index 0000000..20442ad --- /dev/null +++ b/target/linux/s3c24xx/patches-2.6.24/1242-fix-bq27000-charger-state-tracking.patch.patch @@ -0,0 +1,280 @@ +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 + |