From b3d44fcb57173b7995bf67a88aa24aa447f74f52 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Wed, 7 Apr 2010 19:59:26 +0000 Subject: Gigabeat S: Add some sanity checks for a strange charging anomaly that I have personally witnessed twice-- no, I don't have photos or a YT video but it did happen. Details are given in a comment in powermgmt-imx31.c. If it happens again, the checks may serve to reveal the true cause. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25524 a1c6a512-1295-4272-9138-f99709370657 --- .../target/arm/imx31/gigabeat-s/powermgmt-imx31.c | 91 ++++++++++++++++------ .../target/arm/imx31/gigabeat-s/powermgmt-target.h | 4 + 2 files changed, 72 insertions(+), 23 deletions(-) (limited to 'firmware') diff --git a/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c b/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c index 6986a0605d..bb9b8c23af 100644 --- a/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c @@ -379,42 +379,77 @@ static bool adjust_charger_current(void) if (charger_setting != 0) { - charging_set_thread_priority(true); + if ((charger_setting & MC13783_VCHRG) > BATTERY_VCHARGING || + (charger_setting & MC13783_ICHRG) > BATTERY_IFAST) + { + /* Table is corrupted somehow. We shouldn't run at all. + * + * Explanation: On two occasions, even though this driver monitors + * the regulator register settings on each step and + * ensures that only valid table indexes are used, + * the current and voltage seem to be misregulated, + * resulting in excessively high battery voltage that + * will trip the battery protection. After careful + * review it seems that two possibilities exist: + * This code or data got trashed at some point or + * there really is a hardware bug of some sort. So + * far the cause is unknown. Voltage is also + * monitored in the CHARGING case for that reason. + * The solution for data or code corruption is to + * just panic and refuse to run the device. The + * solution for overvoltage due to hardware bug is to + * disable the charging. The action taken will reveal + * the true cause, thus _who_ is responsible. + * "Burning lithium is baaaad", so sayeth The Council + * of Seven Ascended Masters. */ + charge_state = CHARGE_STATE_DISABLED; + service_wdt = false; + } + else + { + /* Turn on 5K pulldown. */ + i = mc13783_set(MC13783_CHARGER, MC13783_CHRGRAWPDEN); - /* Turn regulator logically ON. Hardware may still override. */ - i = mc13783_write_masked(MC13783_CHARGER, - charger_setting | MC13783_CHRGRAWPDEN, - MC13783_ICHRG | MC13783_VCHRG | - MC13783_CHRGRAWPDEN); + if (i != MC13783_DATA_ERROR) + { + charging_set_thread_priority(true); - if (i != MC13783_DATA_ERROR) - { - int icharger; + /* Turn regulator logically ON. Hardware may still override. + */ + i = mc13783_write_masked(MC13783_CHARGER, charger_setting, + MC13783_ICHRG | MC13783_VCHRG); - /* Enable charge current conversion */ - adc_enable_channel(ADC_CHARGER_CURRENT, true); + if (i != MC13783_DATA_ERROR) + { + int icharger; - /* Charge path regulator turn on takes ~100ms max. */ - sleep(HZ/10); + /* Enable charge current conversion */ + adc_enable_channel(ADC_CHARGER_CURRENT, true); - icharger = stat_battery_reading(ADC_CHARGER_CURRENT); + /* Charge path regulator turn on takes ~100ms max. */ + sleep(HZ/10); - if (icharger != INT_MIN) - { - icharger_ave = icharger * ICHARGER_AVE_SAMPLES; + icharger = stat_battery_reading(ADC_CHARGER_CURRENT); + + if (icharger != INT_MIN) + { + icharger_ave = icharger * ICHARGER_AVE_SAMPLES; - if (update_filtered_battery_voltage()) - return true; + if (update_filtered_battery_voltage()) + return true; + } + } } - } - /* Force regulator OFF. */ - charge_state = CHARGE_STATE_ERROR; + /* Force regulator OFF. */ + charge_state = CHARGE_STATE_ERROR; + } } /* Turn regulator OFF. */ icharger_ave = 0; - i = mc13783_write_masked(MC13783_CHARGER, charger_bits[0][0], + i = mc13783_write_masked(MC13783_CHARGER, + MC13783_ICHRG_0MA | MC13783_VCHRG_4_050V, MC13783_ICHRG | MC13783_VCHRG | MC13783_CHRGRAWPDEN); @@ -533,6 +568,16 @@ static bool charging_ok(void) if (charger_setting != 0) { + if (ok) + { + /* Protect against any conceivable overcharge/voltage condition + * before hardware protection must intervene. Disable charger + * until reboot. */ + ok = battery_voltage() < BATT_TOO_HIGH; + if (!ok) + charge_state = CHARGE_STATE_DISABLED; + } + if (ok) { /* Watch to not overheat FET (nothing should go over about 1012.7mW). diff --git a/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h b/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h index 86278bce73..02d94015a1 100644 --- a/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h @@ -59,6 +59,10 @@ #define BATT_USB_VSTOP 4140 /* When to "stop" when USB only */ #define BATT_TOO_LOW 2400 /* No battery? Short? Can't read below 2400mV. */ +#define BATT_TOO_HIGH 4220 /* Extra care. Don't totally + rely upon battery protection + circutry. Stop it early if too + high. */ #define CHARGER_TOTAL_TIMER 300 /* minutes */ /* Temperature readings - w/hysteresis */ -- cgit v1.2.3