diff options
Diffstat (limited to 'firmware/powermgmt.c')
-rw-r--r-- | firmware/powermgmt.c | 252 |
1 files changed, 169 insertions, 83 deletions
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index 008e4a45cb..b4f8aab815 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c @@ -86,7 +86,14 @@ void handle_auto_poweroff(void); static int poweroff_timeout = 0; static long last_event_tick = 0; -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) +#if (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) == PERCENTAGE_MEASURE +int _battery_voltage(void) { return -1; } + +const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11]; +const unsigned short percent_to_volt_charge[11]; + +#elif (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE) == VOLTAGE_MEASURE +int _battery_level(void) { return -1; } /* * Average battery voltage and charger voltage, filtered via a digital * exponential filter (aka. exponential moving average, scaled): @@ -95,10 +102,22 @@ static long last_event_tick = 0; static unsigned int avgbat; /* filtered battery voltage, millivolts */ static unsigned int battery_millivolts; +#elif (CONFIG_BATTERY_MEASURE == 0) +int _battery_voltage(void) { return -1; } +int _battery_level(void) { return -1; } + +const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11]; +const unsigned short percent_to_volt_charge[11]; +#endif + +#if !(CONFIG_BATTERY_MEASURE & TIME_MEASURE) +static int powermgmt_est_runningtime_min; +int _battery_time(void) { return powermgmt_est_runningtime_min; } +#endif + /* default value, mAh */ static int battery_capacity = BATTERY_CAPACITY_DEFAULT; - #if BATTERY_TYPES_COUNT > 1 static int battery_type = 0; #else @@ -115,7 +134,6 @@ static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK]; #endif static const char power_thread_name[] = "power"; -static int powermgmt_est_runningtime_min = -1; static int voltage_to_battery_level(int battery_millivolts); static void battery_status_update(void); @@ -126,13 +144,18 @@ static int runcurrent(void); void battery_read_info(int *voltage, int *level) { - int millivolts = battery_adc_voltage(); + int millivolts = _battery_voltage(); + int percent; if (voltage) *voltage = millivolts; - if (level) - *level = voltage_to_battery_level(millivolts); + if (level) { + percent = voltage_to_battery_level(millivolts); + if (percent < 0) + percent = _battery_level(); + *level = percent; + } } #if BATTERY_TYPES_COUNT > 1 @@ -148,6 +171,7 @@ void set_battery_type(int type) } #endif +#ifdef BATTERY_CAPACITY_MIN void set_battery_capacity(int capacity) { if (capacity > BATTERY_CAPACITY_MAX) @@ -159,6 +183,7 @@ void set_battery_capacity(int capacity) battery_status_update(); /* recalculate the battery status */ } +#endif int get_battery_capacity(void) { @@ -167,7 +192,16 @@ int get_battery_capacity(void) int battery_time(void) { - return powermgmt_est_runningtime_min; +#if ((CONFIG_BATTERY_MEASURE & TIME_MEASURE) == 0) + +#ifndef CURRENT_NORMAL /* no estimation without current */ + return -1; +#endif + if (battery_capacity <= 0) /* nor without capacity */ + return -1; + +#endif + return _battery_time(); } /* Returns battery level in percent */ @@ -180,17 +214,13 @@ int battery_level(void) return battery_percent; } -/* Returns filtered battery voltage [millivolts] */ -unsigned int battery_voltage(void) -{ - return battery_millivolts; -} - /* Tells if the battery level is safe for disk writes */ bool battery_level_safe(void) { #if defined(NO_LOW_BATTERY_SHUTDOWN) return true; +#elif (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) + return (battery_percent > 0); #elif defined(HAVE_BATTERY_SWITCH) /* Cannot rely upon the battery reading to be valid and the * device could be powered externally. */ @@ -228,6 +258,9 @@ static int voltage_to_battery_level(int battery_millivolts) { int level; + if (battery_millivolts < 0) + return -1; + #if CONFIG_CHARGING >= CHARGING_MONITOR if (charging_state()) { /* battery level is defined to be < 100% until charging is finished */ @@ -249,7 +282,8 @@ static int voltage_to_battery_level(int battery_millivolts) static void battery_status_update(void) { - int level = voltage_to_battery_level(battery_millivolts); + int millivolt, level; + battery_read_info(&millivolt, &level); #ifdef CURRENT_NORMAL /*don't try to estimate run or charge time without normal current defined*/ @@ -264,7 +298,8 @@ static void battery_status_update(void) #endif /* discharging: remaining running time */ - if (battery_millivolts > percent_to_volt_discharge[0][0]) { + if (level > 0 && (millivolt > percent_to_volt_discharge[battery_type][0] + || millivolt < 0)) { /* linear extrapolation */ powermgmt_est_runningtime_min = (level + battery_percent)*60 * battery_capacity / 200 / runcurrent(); @@ -272,8 +307,6 @@ static void battery_status_update(void) if (0 > powermgmt_est_runningtime_min) { powermgmt_est_runningtime_min = 0; } -#else - powermgmt_est_runningtime_min=-1; #endif battery_percent = level; @@ -348,6 +381,8 @@ bool query_force_shutdown(void) { #if defined(NO_LOW_BATTERY_SHUTDOWN) return false; +#elif CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE + return battery_percent == 0; #elif defined(HAVE_BATTERY_SWITCH) /* Cannot rely upon the battery reading to be valid and the * device could be powered externally. */ @@ -490,6 +525,101 @@ static inline bool detect_charger(unsigned int pwr) } #endif /* CONFIG_CHARGING */ + +#if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE +/* Returns filtered battery voltage [millivolts] */ +int battery_voltage(void) +{ + return battery_millivolts; +} + +static void average_init(void) +{ + /* initialize the voltages for the exponential filter */ + avgbat = _battery_voltage() + 15; + +#ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */ + /* The battery voltage is usually a little lower directly after + turning on, because the disk was used heavily. Raise it by 5% */ +#if CONFIG_CHARGING + if (!charger_inserted()) /* only if charger not connected */ +#endif + { + avgbat += (percent_to_volt_discharge[battery_type][6] - + percent_to_volt_discharge[battery_type][5]) / 2; + } +#endif /* HAVE_DISK_STORAGE */ + + avgbat = avgbat * BATT_AVE_SAMPLES; + battery_millivolts = power_history[0] = avgbat / BATT_AVE_SAMPLES; +} + +static void average_step(void) +{ + avgbat += _battery_voltage() - avgbat / BATT_AVE_SAMPLES; + /* + * battery_millivolts is the millivolt-scaled filtered battery value. + */ + battery_millivolts = avgbat / BATT_AVE_SAMPLES; +} + +static void average_step_low(void) +{ + battery_millivolts = (_battery_voltage() + battery_millivolts + 1) / 2; + avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES; +} + +static void init_battery_percent(void) +{ +#if CONFIG_CHARGING + if (charger_inserted()) { + battery_percent = voltage_to_percent(battery_millivolts, + percent_to_volt_charge); + } + else +#endif + { + battery_percent = voltage_to_percent(battery_millivolts, + percent_to_volt_discharge[battery_type]); + battery_percent += battery_percent < 100; + } + +} + +static int power_hist_item(void) +{ + return battery_millivolts; +} +#define power_history_unit() battery_millivolts + +#else +int battery_voltage(void) +{ + return -1; +} + +static void average_init(void) {} +static void average_step(void) {} +static void average_step_low(void) {} +static void init_battery_percent(void) +{ + battery_percent = _battery_level(); +} + +static int power_hist_item(void) +{ + return battery_percent; +} +#endif + +static void collect_power_history(void) +{ + /* rotate the power history */ + memmove(&power_history[1], &power_history[0], + sizeof(power_history) - sizeof(power_history[0])); + power_history[0] = power_hist_item(); +} + /* * Monitor the presence of a charger and perform critical frequent steps * such as running the battery voltage filter. @@ -519,33 +649,23 @@ static inline void power_thread_step(void) || charger_input_state == CHARGER #endif ) { - avgbat += battery_adc_voltage() - avgbat / BATT_AVE_SAMPLES; - /* - * battery_millivolts is the millivolt-scaled filtered battery value. - */ - battery_millivolts = avgbat / BATT_AVE_SAMPLES; - + average_step(); /* update battery status every time an update is available */ battery_status_update(); } else if (battery_percent < 8) { + average_step_low(); + /* update battery status every time an update is available */ + battery_status_update(); + /* * If battery is low, observe voltage during disk activity. * Shut down if voltage drops below shutoff level and we are not * using NiMH or Alkaline batteries. */ - battery_millivolts = (battery_adc_voltage() + - battery_millivolts + 1) / 2; - - /* update battery status every time an update is available */ - battery_status_update(); - if (!shutdown_timeout && query_force_shutdown()) { sys_poweroff(); } - else { - avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES; - } } } /* power_thread_step */ @@ -555,7 +675,7 @@ static void power_thread(void) /* Delay reading the first battery level */ #ifdef MROBE_100 - while (battery_adc_voltage() > 4200) /* gives false readings initially */ + while (_battery_voltage() > 4200) /* gives false readings initially */ #endif { sleep(HZ/100); @@ -566,38 +686,13 @@ static void power_thread(void) power_thread_inputs = power_input_status(); #endif - /* initialize the voltages for the exponential filter */ - avgbat = battery_adc_voltage() + 15; - -#ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */ - /* The battery voltage is usually a little lower directly after - turning on, because the disk was used heavily. Raise it by 5% */ -#if CONFIG_CHARGING - if (!charger_inserted()) /* only if charger not connected */ -#endif - { - avgbat += (percent_to_volt_discharge[battery_type][6] - - percent_to_volt_discharge[battery_type][5]) / 2; - } -#endif /* HAVE_DISK_STORAGE */ - - avgbat = avgbat * BATT_AVE_SAMPLES; - battery_millivolts = avgbat / BATT_AVE_SAMPLES; - power_history[0] = battery_millivolts; - -#if CONFIG_CHARGING - if (charger_inserted()) { - battery_percent = voltage_to_percent(battery_millivolts, - percent_to_volt_charge); - } - else -#endif - { - battery_percent = voltage_to_percent(battery_millivolts, - percent_to_volt_discharge[battery_type]); - battery_percent += battery_percent < 100; - } - + /* initialize voltage averaging (if available) */ + average_init(); + /* get initial battery level value (in %) */ + init_battery_percent(); + /* get some initial data for the power curve */ + collect_power_history(); + /* call target specific init now */ powermgmt_init_target(); next_power_hist = current_tick + HZ*60; @@ -609,7 +704,7 @@ static void power_thread(void) #ifdef HAVE_BATTERY_SWITCH if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) { sleep(HZ/10); - reset_battery_filter(battery_adc_voltage()); + reset_battery_filter(_battery_voltage()); } #endif power_thread_inputs = pwr; @@ -627,21 +722,15 @@ static void power_thread(void) /* Perform target tasks */ charging_algorithm_step(); - if (TIME_BEFORE(current_tick, next_power_hist)) - continue; - - /* increment to ensure there is a record for every minute - * rather than go forward from the current tick */ - next_power_hist += HZ*60; - - /* rotate the power history */ - memmove(&power_history[1], &power_history[0], - sizeof(power_history) - sizeof(power_history[0])); - - /* insert new value at the start, in millivolts 8-) */ - power_history[0] = battery_millivolts; - + /* check if some idle or sleep timer wears off */ handle_auto_poweroff(); + + if (TIME_AFTER(current_tick, next_power_hist)) { + /* increment to ensure there is a record for every minute + * rather than go forward from the current tick */ + next_power_hist += HZ*60; + collect_power_history(); + } } } /* power_thread */ @@ -701,7 +790,6 @@ void shutdown_hw(void) sleep(HZ/4); power_off(); } -#endif /* PLATFORM_NATIVE */ void set_poweroff_timeout(int timeout) { @@ -855,12 +943,10 @@ void handle_auto_poweroff(void) last_event_tick = current_tick; } -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) if (!shutdown_timeout && query_force_shutdown()) { backlight_on(); sys_poweroff(); } -#endif if (timeout && #if CONFIG_TUNER |