Index: firmware/export/config-c200.h =================================================================== --- firmware/export/config-c200.h (revision 18278) +++ firmware/export/config-c200.h (working copy) @@ -123,8 +123,8 @@ #define BATTERY_CAPACITY_INC 0 /* capacity increment */ #define BATTERY_TYPES_COUNT 1 /* only one type */ -/* Hardware controlled charging? FIXME */ -#define CONFIG_CHARGING CHARGING_SIMPLE +/* Hardware controlled charging with monitoring of charge status */ +#define CONFIG_CHARGING CHARGING_MONITOR /* define this if the unit can be powered or charged via USB */ #define HAVE_USB_POWER Index: firmware/export/config-e200.h =================================================================== --- firmware/export/config-e200.h (revision 18278) +++ firmware/export/config-e200.h (working copy) @@ -120,8 +120,8 @@ #define BATTERY_CAPACITY_INC 0 /* capacity increment */ #define BATTERY_TYPES_COUNT 1 /* only one type */ -/* Hardware controlled charging? FIXME */ -#define CONFIG_CHARGING CHARGING_SIMPLE +/* Hardware controlled charging with monitoring of charge status */ +#define CONFIG_CHARGING CHARGING_MONITOR /* define this if the unit can be powered or charged via USB */ #define HAVE_USB_POWER Index: firmware/target/arm/sandisk/power-c200_e200.c =================================================================== --- firmware/target/arm/sandisk/power-c200_e200.c (revision 18278) +++ firmware/target/arm/sandisk/power-c200_e200.c (working copy) @@ -27,8 +27,43 @@ #include "as3514.h" #include "power.h" +/* mA, 50 - 400 in steps of 50 */ +#define CHARGE_CURRENT 300 +#if (CHARGE_CURRENT < 50) || (CHARGE_CURRENT > 400) +#error "Charging current out of range" +#endif + +/* mV, 3900 - 4250 in steps of 50 */ +#define CHARGE_VOLTAGE 4200 +#if (CHARGE_VOLTAGE < 3900) || (CHARGE_VOLTAGE > 4200) +#error "Charging voltage out of range" +#endif + +/* charger status bits in AS3514_IRQ_ENRD0 */ +#define CHG_tmphigh (1<<7) +#define CHG_endofch (1<<6) +#define CHG_status (1<<5) +#define CHG_changed (1<<4) + +/* charger control bits in AS3514_CHARGER */ +#define CHG_I (1<<4) +#define CHG_V (1<<1) +#define CHG_OFF (1<<0) + +/* charger states */ +static enum { + STATE_UNPLUGGED, + STATE_CHARGING, + STATE_CHARGED +} charger_state; + + void power_init(void) { + charger_state = STATE_UNPLUGGED; + + /* enable charger status bits */ + pp_i2c_send(AS3514_I2C_ADDR, AS3514_IRQ_ENRD0, 0xF0); } void power_off(void) @@ -53,17 +88,71 @@ } } + bool charger_inserted(void) { + unsigned char status; + + /* check GPIO first */ #ifdef SANSA_E200 if(GPIOB_INPUT_VAL & 0x10) #else /* SANSA_C200 */ if(GPIOH_INPUT_VAL & 0x2) #endif - return true; + { + /* also check charger status bit */ + status = i2c_readbyte(AS3514_I2C_ADDR, AS3514_IRQ_ENRD0); + if (status & CHG_status) + return true; + } + + /* not fully connected yet, keep state machine in reset */ + charger_state = STATE_UNPLUGGED; return false; } +bool charging_state(void) +{ + unsigned char status; + + status = i2c_readbyte(AS3514_I2C_ADDR, AS3514_IRQ_ENRD0); + + switch (charger_state) { + + case STATE_UNPLUGGED: + if (status & CHG_status) + { + /* enable charger */ + pp_i2c_send(AS3514_I2C_ADDR, AS3514_CHARGER, + (((CHARGE_CURRENT - 50) / 50) * CHG_I) | + (((CHARGE_VOLTAGE - 3900) / 50) * CHG_V)); + charger_state = STATE_CHARGING; + } + break; + + case STATE_CHARGING: + if (status & (CHG_endofch | CHG_tmphigh)) + { + /* charging done or battery too hot, stop charging */ + pp_i2c_send(AS3514_I2C_ADDR, AS3514_CHARGER, CHG_OFF); + charger_state = STATE_CHARGED; + } + break; + + case STATE_CHARGED: + /* do nothing, wait for unplug */ + break; + + default: + /* this should never happen... */ + charger_state = STATE_UNPLUGGED; + break; + } + + return (charger_state = STATE_CHARGING); +} + + void ide_power_enable(bool on) { (void)on; Index: firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c =================================================================== --- firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c (revision 18278) +++ firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c (working copy) @@ -55,6 +55,10 @@ /* Returns battery voltage from ADC [millivolts] */ unsigned int battery_adc_voltage(void) { - return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10; + /* on e200 ADC_RTCSUP seems to represent battery voltage better than + ADC_BVDD during charging (ADC_BVDD is way too high) and appears the same + in normal use. + */ + return (adc_read(ADC_RTCSUP) * BATTERY_SCALE_FACTOR) >> 10; }