summaryrefslogtreecommitdiff
path: root/firmware/powermgmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/powermgmt.c')
-rw-r--r--firmware/powermgmt.c252
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);
86static int poweroff_timeout = 0; 86static int poweroff_timeout = 0;
87static long last_event_tick = 0; 87static 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
90int _battery_voltage(void) { return -1; }
91
92const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
93const unsigned short percent_to_volt_charge[11];
94
95#elif (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE) == VOLTAGE_MEASURE
96int _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;
95static unsigned int avgbat; 102static unsigned int avgbat;
96/* filtered battery voltage, millivolts */ 103/* filtered battery voltage, millivolts */
97static unsigned int battery_millivolts; 104static unsigned int battery_millivolts;
105#elif (CONFIG_BATTERY_MEASURE == 0)
106int _battery_voltage(void) { return -1; }
107int _battery_level(void) { return -1; }
108
109const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
110const unsigned short percent_to_volt_charge[11];
111#endif
112
113#if !(CONFIG_BATTERY_MEASURE & TIME_MEASURE)
114static int powermgmt_est_runningtime_min;
115int _battery_time(void) { return powermgmt_est_runningtime_min; }
116#endif
117
98/* default value, mAh */ 118/* default value, mAh */
99static int battery_capacity = BATTERY_CAPACITY_DEFAULT; 119static int battery_capacity = BATTERY_CAPACITY_DEFAULT;
100 120
101
102#if BATTERY_TYPES_COUNT > 1 121#if BATTERY_TYPES_COUNT > 1
103static int battery_type = 0; 122static 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
116static const char power_thread_name[] = "power"; 135static const char power_thread_name[] = "power";
117 136
118static int powermgmt_est_runningtime_min = -1;
119 137
120static int voltage_to_battery_level(int battery_millivolts); 138static int voltage_to_battery_level(int battery_millivolts);
121static void battery_status_update(void); 139static void battery_status_update(void);
@@ -126,13 +144,18 @@ static int runcurrent(void);
126 144
127void battery_read_info(int *voltage, int *level) 145void 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
151void set_battery_capacity(int capacity) 175void 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
163int get_battery_capacity(void) 188int get_battery_capacity(void)
164{ 189{
@@ -167,7 +192,16 @@ int get_battery_capacity(void)
167 192
168int battery_time(void) 193int 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] */
184unsigned 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 */
190bool battery_level_safe(void) 218bool 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
250static void battery_status_update(void) 283static 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] */
531int battery_voltage(void)
532{
533 return battery_millivolts;
534}
535
536static 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
557static 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
566static 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
572static 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
589static int power_hist_item(void)
590{
591 return battery_millivolts;
592}
593#define power_history_unit() battery_millivolts
594
595#else
596int battery_voltage(void)
597{
598 return -1;
599}
600
601static void average_init(void) {}
602static void average_step(void) {}
603static void average_step_low(void) {}
604static void init_battery_percent(void)
605{
606 battery_percent = _battery_level();
607}
608
609static int power_hist_item(void)
610{
611 return battery_percent;
612}
613#endif
614
615static 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
706void set_poweroff_timeout(int timeout) 794void 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