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); | |||
86 | static int poweroff_timeout = 0; | 86 | static int poweroff_timeout = 0; |
87 | static long last_event_tick = 0; | 87 | static long last_event_tick = 0; |
88 | 88 | ||
89 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) | 89 | #if (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) == PERCENTAGE_MEASURE |
90 | int _battery_voltage(void) { return -1; } | ||
91 | |||
92 | const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11]; | ||
93 | const unsigned short percent_to_volt_charge[11]; | ||
94 | |||
95 | #elif (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE) == VOLTAGE_MEASURE | ||
96 | int _battery_level(void) { return -1; } | ||
90 | /* | 97 | /* |
91 | * Average battery voltage and charger voltage, filtered via a digital | 98 | * Average battery voltage and charger voltage, filtered via a digital |
92 | * exponential filter (aka. exponential moving average, scaled): | 99 | * exponential filter (aka. exponential moving average, scaled): |
@@ -95,10 +102,22 @@ static long last_event_tick = 0; | |||
95 | static unsigned int avgbat; | 102 | static unsigned int avgbat; |
96 | /* filtered battery voltage, millivolts */ | 103 | /* filtered battery voltage, millivolts */ |
97 | static unsigned int battery_millivolts; | 104 | static unsigned int battery_millivolts; |
105 | #elif (CONFIG_BATTERY_MEASURE == 0) | ||
106 | int _battery_voltage(void) { return -1; } | ||
107 | int _battery_level(void) { return -1; } | ||
108 | |||
109 | const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11]; | ||
110 | const unsigned short percent_to_volt_charge[11]; | ||
111 | #endif | ||
112 | |||
113 | #if !(CONFIG_BATTERY_MEASURE & TIME_MEASURE) | ||
114 | static int powermgmt_est_runningtime_min; | ||
115 | int _battery_time(void) { return powermgmt_est_runningtime_min; } | ||
116 | #endif | ||
117 | |||
98 | /* default value, mAh */ | 118 | /* default value, mAh */ |
99 | static int battery_capacity = BATTERY_CAPACITY_DEFAULT; | 119 | static int battery_capacity = BATTERY_CAPACITY_DEFAULT; |
100 | 120 | ||
101 | |||
102 | #if BATTERY_TYPES_COUNT > 1 | 121 | #if BATTERY_TYPES_COUNT > 1 |
103 | static int battery_type = 0; | 122 | static int battery_type = 0; |
104 | #else | 123 | #else |
@@ -115,7 +134,6 @@ static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK]; | |||
115 | #endif | 134 | #endif |
116 | static const char power_thread_name[] = "power"; | 135 | static const char power_thread_name[] = "power"; |
117 | 136 | ||
118 | static int powermgmt_est_runningtime_min = -1; | ||
119 | 137 | ||
120 | static int voltage_to_battery_level(int battery_millivolts); | 138 | static int voltage_to_battery_level(int battery_millivolts); |
121 | static void battery_status_update(void); | 139 | static void battery_status_update(void); |
@@ -126,13 +144,18 @@ static int runcurrent(void); | |||
126 | 144 | ||
127 | void battery_read_info(int *voltage, int *level) | 145 | void battery_read_info(int *voltage, int *level) |
128 | { | 146 | { |
129 | int millivolts = battery_adc_voltage(); | 147 | int millivolts = _battery_voltage(); |
148 | int percent; | ||
130 | 149 | ||
131 | if (voltage) | 150 | if (voltage) |
132 | *voltage = millivolts; | 151 | *voltage = millivolts; |
133 | 152 | ||
134 | if (level) | 153 | if (level) { |
135 | *level = voltage_to_battery_level(millivolts); | 154 | percent = voltage_to_battery_level(millivolts); |
155 | if (percent < 0) | ||
156 | percent = _battery_level(); | ||
157 | *level = percent; | ||
158 | } | ||
136 | } | 159 | } |
137 | 160 | ||
138 | #if BATTERY_TYPES_COUNT > 1 | 161 | #if BATTERY_TYPES_COUNT > 1 |
@@ -148,6 +171,7 @@ void set_battery_type(int type) | |||
148 | } | 171 | } |
149 | #endif | 172 | #endif |
150 | 173 | ||
174 | #ifdef BATTERY_CAPACITY_MIN | ||
151 | void set_battery_capacity(int capacity) | 175 | void set_battery_capacity(int capacity) |
152 | { | 176 | { |
153 | if (capacity > BATTERY_CAPACITY_MAX) | 177 | if (capacity > BATTERY_CAPACITY_MAX) |
@@ -159,6 +183,7 @@ void set_battery_capacity(int capacity) | |||
159 | 183 | ||
160 | battery_status_update(); /* recalculate the battery status */ | 184 | battery_status_update(); /* recalculate the battery status */ |
161 | } | 185 | } |
186 | #endif | ||
162 | 187 | ||
163 | int get_battery_capacity(void) | 188 | int get_battery_capacity(void) |
164 | { | 189 | { |
@@ -167,7 +192,16 @@ int get_battery_capacity(void) | |||
167 | 192 | ||
168 | int battery_time(void) | 193 | int battery_time(void) |
169 | { | 194 | { |
170 | return powermgmt_est_runningtime_min; | 195 | #if ((CONFIG_BATTERY_MEASURE & TIME_MEASURE) == 0) |
196 | |||
197 | #ifndef CURRENT_NORMAL /* no estimation without current */ | ||
198 | return -1; | ||
199 | #endif | ||
200 | if (battery_capacity <= 0) /* nor without capacity */ | ||
201 | return -1; | ||
202 | |||
203 | #endif | ||
204 | return _battery_time(); | ||
171 | } | 205 | } |
172 | 206 | ||
173 | /* Returns battery level in percent */ | 207 | /* Returns battery level in percent */ |
@@ -180,17 +214,13 @@ int battery_level(void) | |||
180 | return battery_percent; | 214 | return battery_percent; |
181 | } | 215 | } |
182 | 216 | ||
183 | /* Returns filtered battery voltage [millivolts] */ | ||
184 | unsigned int battery_voltage(void) | ||
185 | { | ||
186 | return battery_millivolts; | ||
187 | } | ||
188 | |||
189 | /* Tells if the battery level is safe for disk writes */ | 217 | /* Tells if the battery level is safe for disk writes */ |
190 | bool battery_level_safe(void) | 218 | bool battery_level_safe(void) |
191 | { | 219 | { |
192 | #if defined(NO_LOW_BATTERY_SHUTDOWN) | 220 | #if defined(NO_LOW_BATTERY_SHUTDOWN) |
193 | return true; | 221 | return true; |
222 | #elif (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) | ||
223 | return (battery_percent > 0); | ||
194 | #elif defined(HAVE_BATTERY_SWITCH) | 224 | #elif defined(HAVE_BATTERY_SWITCH) |
195 | /* Cannot rely upon the battery reading to be valid and the | 225 | /* Cannot rely upon the battery reading to be valid and the |
196 | * device could be powered externally. */ | 226 | * device could be powered externally. */ |
@@ -228,6 +258,9 @@ static int voltage_to_battery_level(int battery_millivolts) | |||
228 | { | 258 | { |
229 | int level; | 259 | int level; |
230 | 260 | ||
261 | if (battery_millivolts < 0) | ||
262 | return -1; | ||
263 | |||
231 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 264 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
232 | if (charging_state()) { | 265 | if (charging_state()) { |
233 | /* battery level is defined to be < 100% until charging is finished */ | 266 | /* battery level is defined to be < 100% until charging is finished */ |
@@ -249,7 +282,8 @@ static int voltage_to_battery_level(int battery_millivolts) | |||
249 | 282 | ||
250 | static void battery_status_update(void) | 283 | static void battery_status_update(void) |
251 | { | 284 | { |
252 | int level = voltage_to_battery_level(battery_millivolts); | 285 | int millivolt, level; |
286 | battery_read_info(&millivolt, &level); | ||
253 | 287 | ||
254 | #ifdef CURRENT_NORMAL /*don't try to estimate run or charge | 288 | #ifdef CURRENT_NORMAL /*don't try to estimate run or charge |
255 | time without normal current defined*/ | 289 | time without normal current defined*/ |
@@ -264,7 +298,8 @@ static void battery_status_update(void) | |||
264 | #endif | 298 | #endif |
265 | 299 | ||
266 | /* discharging: remaining running time */ | 300 | /* discharging: remaining running time */ |
267 | if (battery_millivolts > percent_to_volt_discharge[0][0]) { | 301 | if (level > 0 && (millivolt > percent_to_volt_discharge[battery_type][0] |
302 | || millivolt < 0)) { | ||
268 | /* linear extrapolation */ | 303 | /* linear extrapolation */ |
269 | powermgmt_est_runningtime_min = (level + battery_percent)*60 | 304 | powermgmt_est_runningtime_min = (level + battery_percent)*60 |
270 | * battery_capacity / 200 / runcurrent(); | 305 | * battery_capacity / 200 / runcurrent(); |
@@ -272,8 +307,6 @@ static void battery_status_update(void) | |||
272 | if (0 > powermgmt_est_runningtime_min) { | 307 | if (0 > powermgmt_est_runningtime_min) { |
273 | powermgmt_est_runningtime_min = 0; | 308 | powermgmt_est_runningtime_min = 0; |
274 | } | 309 | } |
275 | #else | ||
276 | powermgmt_est_runningtime_min=-1; | ||
277 | #endif | 310 | #endif |
278 | 311 | ||
279 | battery_percent = level; | 312 | battery_percent = level; |
@@ -348,6 +381,8 @@ bool query_force_shutdown(void) | |||
348 | { | 381 | { |
349 | #if defined(NO_LOW_BATTERY_SHUTDOWN) | 382 | #if defined(NO_LOW_BATTERY_SHUTDOWN) |
350 | return false; | 383 | return false; |
384 | #elif CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE | ||
385 | return battery_percent == 0; | ||
351 | #elif defined(HAVE_BATTERY_SWITCH) | 386 | #elif defined(HAVE_BATTERY_SWITCH) |
352 | /* Cannot rely upon the battery reading to be valid and the | 387 | /* Cannot rely upon the battery reading to be valid and the |
353 | * device could be powered externally. */ | 388 | * device could be powered externally. */ |
@@ -490,6 +525,101 @@ static inline bool detect_charger(unsigned int pwr) | |||
490 | } | 525 | } |
491 | #endif /* CONFIG_CHARGING */ | 526 | #endif /* CONFIG_CHARGING */ |
492 | 527 | ||
528 | |||
529 | #if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE | ||
530 | /* Returns filtered battery voltage [millivolts] */ | ||
531 | int battery_voltage(void) | ||
532 | { | ||
533 | return battery_millivolts; | ||
534 | } | ||
535 | |||
536 | static void average_init(void) | ||
537 | { | ||
538 | /* initialize the voltages for the exponential filter */ | ||
539 | avgbat = _battery_voltage() + 15; | ||
540 | |||
541 | #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */ | ||
542 | /* The battery voltage is usually a little lower directly after | ||
543 | turning on, because the disk was used heavily. Raise it by 5% */ | ||
544 | #if CONFIG_CHARGING | ||
545 | if (!charger_inserted()) /* only if charger not connected */ | ||
546 | #endif | ||
547 | { | ||
548 | avgbat += (percent_to_volt_discharge[battery_type][6] - | ||
549 | percent_to_volt_discharge[battery_type][5]) / 2; | ||
550 | } | ||
551 | #endif /* HAVE_DISK_STORAGE */ | ||
552 | |||
553 | avgbat = avgbat * BATT_AVE_SAMPLES; | ||
554 | battery_millivolts = power_history[0] = avgbat / BATT_AVE_SAMPLES; | ||
555 | } | ||
556 | |||
557 | static void average_step(void) | ||
558 | { | ||
559 | avgbat += _battery_voltage() - avgbat / BATT_AVE_SAMPLES; | ||
560 | /* | ||
561 | * battery_millivolts is the millivolt-scaled filtered battery value. | ||
562 | */ | ||
563 | battery_millivolts = avgbat / BATT_AVE_SAMPLES; | ||
564 | } | ||
565 | |||
566 | static void average_step_low(void) | ||
567 | { | ||
568 | battery_millivolts = (_battery_voltage() + battery_millivolts + 1) / 2; | ||
569 | avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES; | ||
570 | } | ||
571 | |||
572 | static void init_battery_percent(void) | ||
573 | { | ||
574 | #if CONFIG_CHARGING | ||
575 | if (charger_inserted()) { | ||
576 | battery_percent = voltage_to_percent(battery_millivolts, | ||
577 | percent_to_volt_charge); | ||
578 | } | ||
579 | else | ||
580 | #endif | ||
581 | { | ||
582 | battery_percent = voltage_to_percent(battery_millivolts, | ||
583 | percent_to_volt_discharge[battery_type]); | ||
584 | battery_percent += battery_percent < 100; | ||
585 | } | ||
586 | |||
587 | } | ||
588 | |||
589 | static int power_hist_item(void) | ||
590 | { | ||
591 | return battery_millivolts; | ||
592 | } | ||
593 | #define power_history_unit() battery_millivolts | ||
594 | |||
595 | #else | ||
596 | int battery_voltage(void) | ||
597 | { | ||
598 | return -1; | ||
599 | } | ||
600 | |||
601 | static void average_init(void) {} | ||
602 | static void average_step(void) {} | ||
603 | static void average_step_low(void) {} | ||
604 | static void init_battery_percent(void) | ||
605 | { | ||
606 | battery_percent = _battery_level(); | ||
607 | } | ||
608 | |||
609 | static int power_hist_item(void) | ||
610 | { | ||
611 | return battery_percent; | ||
612 | } | ||
613 | #endif | ||
614 | |||
615 | static void collect_power_history(void) | ||
616 | { | ||
617 | /* rotate the power history */ | ||
618 | memmove(&power_history[1], &power_history[0], | ||
619 | sizeof(power_history) - sizeof(power_history[0])); | ||
620 | power_history[0] = power_hist_item(); | ||
621 | } | ||
622 | |||
493 | /* | 623 | /* |
494 | * Monitor the presence of a charger and perform critical frequent steps | 624 | * Monitor the presence of a charger and perform critical frequent steps |
495 | * such as running the battery voltage filter. | 625 | * such as running the battery voltage filter. |
@@ -519,33 +649,23 @@ static inline void power_thread_step(void) | |||
519 | || charger_input_state == CHARGER | 649 | || charger_input_state == CHARGER |
520 | #endif | 650 | #endif |
521 | ) { | 651 | ) { |
522 | avgbat += battery_adc_voltage() - avgbat / BATT_AVE_SAMPLES; | 652 | average_step(); |
523 | /* | ||
524 | * battery_millivolts is the millivolt-scaled filtered battery value. | ||
525 | */ | ||
526 | battery_millivolts = avgbat / BATT_AVE_SAMPLES; | ||
527 | |||
528 | /* update battery status every time an update is available */ | 653 | /* update battery status every time an update is available */ |
529 | battery_status_update(); | 654 | battery_status_update(); |
530 | } | 655 | } |
531 | else if (battery_percent < 8) { | 656 | else if (battery_percent < 8) { |
657 | average_step_low(); | ||
658 | /* update battery status every time an update is available */ | ||
659 | battery_status_update(); | ||
660 | |||
532 | /* | 661 | /* |
533 | * If battery is low, observe voltage during disk activity. | 662 | * If battery is low, observe voltage during disk activity. |
534 | * Shut down if voltage drops below shutoff level and we are not | 663 | * Shut down if voltage drops below shutoff level and we are not |
535 | * using NiMH or Alkaline batteries. | 664 | * using NiMH or Alkaline batteries. |
536 | */ | 665 | */ |
537 | battery_millivolts = (battery_adc_voltage() + | ||
538 | battery_millivolts + 1) / 2; | ||
539 | |||
540 | /* update battery status every time an update is available */ | ||
541 | battery_status_update(); | ||
542 | |||
543 | if (!shutdown_timeout && query_force_shutdown()) { | 666 | if (!shutdown_timeout && query_force_shutdown()) { |
544 | sys_poweroff(); | 667 | sys_poweroff(); |
545 | } | 668 | } |
546 | else { | ||
547 | avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES; | ||
548 | } | ||
549 | } | 669 | } |
550 | } /* power_thread_step */ | 670 | } /* power_thread_step */ |
551 | 671 | ||
@@ -555,7 +675,7 @@ static void power_thread(void) | |||
555 | 675 | ||
556 | /* Delay reading the first battery level */ | 676 | /* Delay reading the first battery level */ |
557 | #ifdef MROBE_100 | 677 | #ifdef MROBE_100 |
558 | while (battery_adc_voltage() > 4200) /* gives false readings initially */ | 678 | while (_battery_voltage() > 4200) /* gives false readings initially */ |
559 | #endif | 679 | #endif |
560 | { | 680 | { |
561 | sleep(HZ/100); | 681 | sleep(HZ/100); |
@@ -566,38 +686,13 @@ static void power_thread(void) | |||
566 | power_thread_inputs = power_input_status(); | 686 | power_thread_inputs = power_input_status(); |
567 | #endif | 687 | #endif |
568 | 688 | ||
569 | /* initialize the voltages for the exponential filter */ | 689 | /* initialize voltage averaging (if available) */ |
570 | avgbat = battery_adc_voltage() + 15; | 690 | average_init(); |
571 | 691 | /* get initial battery level value (in %) */ | |
572 | #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */ | 692 | init_battery_percent(); |
573 | /* The battery voltage is usually a little lower directly after | 693 | /* get some initial data for the power curve */ |
574 | turning on, because the disk was used heavily. Raise it by 5% */ | 694 | collect_power_history(); |
575 | #if CONFIG_CHARGING | 695 | /* call target specific init now */ |
576 | if (!charger_inserted()) /* only if charger not connected */ | ||
577 | #endif | ||
578 | { | ||
579 | avgbat += (percent_to_volt_discharge[battery_type][6] - | ||
580 | percent_to_volt_discharge[battery_type][5]) / 2; | ||
581 | } | ||
582 | #endif /* HAVE_DISK_STORAGE */ | ||
583 | |||
584 | avgbat = avgbat * BATT_AVE_SAMPLES; | ||
585 | battery_millivolts = avgbat / BATT_AVE_SAMPLES; | ||
586 | power_history[0] = battery_millivolts; | ||
587 | |||
588 | #if CONFIG_CHARGING | ||
589 | if (charger_inserted()) { | ||
590 | battery_percent = voltage_to_percent(battery_millivolts, | ||
591 | percent_to_volt_charge); | ||
592 | } | ||
593 | else | ||
594 | #endif | ||
595 | { | ||
596 | battery_percent = voltage_to_percent(battery_millivolts, | ||
597 | percent_to_volt_discharge[battery_type]); | ||
598 | battery_percent += battery_percent < 100; | ||
599 | } | ||
600 | |||
601 | powermgmt_init_target(); | 696 | powermgmt_init_target(); |
602 | 697 | ||
603 | next_power_hist = current_tick + HZ*60; | 698 | next_power_hist = current_tick + HZ*60; |
@@ -609,7 +704,7 @@ static void power_thread(void) | |||
609 | #ifdef HAVE_BATTERY_SWITCH | 704 | #ifdef HAVE_BATTERY_SWITCH |
610 | if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) { | 705 | if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) { |
611 | sleep(HZ/10); | 706 | sleep(HZ/10); |
612 | reset_battery_filter(battery_adc_voltage()); | 707 | reset_battery_filter(_battery_voltage()); |
613 | } | 708 | } |
614 | #endif | 709 | #endif |
615 | power_thread_inputs = pwr; | 710 | power_thread_inputs = pwr; |
@@ -627,21 +722,15 @@ static void power_thread(void) | |||
627 | /* Perform target tasks */ | 722 | /* Perform target tasks */ |
628 | charging_algorithm_step(); | 723 | charging_algorithm_step(); |
629 | 724 | ||
630 | if (TIME_BEFORE(current_tick, next_power_hist)) | 725 | /* check if some idle or sleep timer wears off */ |
631 | continue; | ||
632 | |||
633 | /* increment to ensure there is a record for every minute | ||
634 | * rather than go forward from the current tick */ | ||
635 | next_power_hist += HZ*60; | ||
636 | |||
637 | /* rotate the power history */ | ||
638 | memmove(&power_history[1], &power_history[0], | ||
639 | sizeof(power_history) - sizeof(power_history[0])); | ||
640 | |||
641 | /* insert new value at the start, in millivolts 8-) */ | ||
642 | power_history[0] = battery_millivolts; | ||
643 | |||
644 | handle_auto_poweroff(); | 726 | handle_auto_poweroff(); |
727 | |||
728 | if (TIME_AFTER(current_tick, next_power_hist)) { | ||
729 | /* increment to ensure there is a record for every minute | ||
730 | * rather than go forward from the current tick */ | ||
731 | next_power_hist += HZ*60; | ||
732 | collect_power_history(); | ||
733 | } | ||
645 | } | 734 | } |
646 | } /* power_thread */ | 735 | } /* power_thread */ |
647 | 736 | ||
@@ -701,7 +790,6 @@ void shutdown_hw(void) | |||
701 | sleep(HZ/4); | 790 | sleep(HZ/4); |
702 | power_off(); | 791 | power_off(); |
703 | } | 792 | } |
704 | #endif /* PLATFORM_NATIVE */ | ||
705 | 793 | ||
706 | void set_poweroff_timeout(int timeout) | 794 | void set_poweroff_timeout(int timeout) |
707 | { | 795 | { |
@@ -855,12 +943,10 @@ void handle_auto_poweroff(void) | |||
855 | last_event_tick = current_tick; | 943 | last_event_tick = current_tick; |
856 | } | 944 | } |
857 | 945 | ||
858 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) | ||
859 | if (!shutdown_timeout && query_force_shutdown()) { | 946 | if (!shutdown_timeout && query_force_shutdown()) { |
860 | backlight_on(); | 947 | backlight_on(); |
861 | sys_poweroff(); | 948 | sys_poweroff(); |
862 | } | 949 | } |
863 | #endif | ||
864 | 950 | ||
865 | if (timeout && | 951 | if (timeout && |
866 | #if CONFIG_TUNER | 952 | #if CONFIG_TUNER |