Remove some old archos code that caused runtime estimation to be off on AMS players...
[kugel-rb.git] / firmware / powermgmt.c
blobf8c3995e1a827d093e8f77687828be7182a3939c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese
11 * Revisions copyright (C) 2005 by Gerald Van Baren
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include "config.h"
23 #include "system.h"
24 #include "kernel.h"
25 #include "thread.h"
26 #include "debug.h"
27 #include "adc.h"
28 #include "string.h"
29 #include "storage.h"
30 #include "power.h"
31 #include "audio.h"
32 #include "mp3_playback.h"
33 #include "usb.h"
34 #include "powermgmt.h"
35 #include "backlight.h"
36 #include "lcd.h"
37 #include "rtc.h"
38 #if CONFIG_TUNER
39 #include "fmradio.h"
40 #endif
41 #include "sound.h"
42 #ifdef HAVE_LCD_BITMAP
43 #include "font.h"
44 #endif
45 #include "logf.h"
46 #include "lcd-remote.h"
47 #ifdef SIMULATOR
48 #include <time.h>
49 #endif
51 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5)) && !defined (SIMULATOR)
52 #include "lcd-remote-target.h"
53 #endif
54 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) \
55 && !defined (SIMULATOR)
56 #include "pcf50606.h"
57 #endif
59 /** Shared by sim **/
60 int last_sent_battery_level = 100;
61 /* battery level (0-100%) */
62 int battery_percent = -1;
63 void send_battery_level_event(void);
65 #if CONFIG_CHARGING
66 /* State of the charger input as seen by the power thread */
67 enum charger_input_state_type charger_input_state;
68 /* Power inputs as seen by the power thread */
69 unsigned int power_thread_inputs;
70 #if CONFIG_CHARGING >= CHARGING_MONITOR
71 /* Charging state (mode) as seen by the power thread */
72 enum charge_state_type charge_state = DISCHARGING;
73 #endif
74 #endif /* CONFIG_CHARGING */
76 #ifndef SIMULATOR
77 static int shutdown_timeout = 0;
79 * Average battery voltage and charger voltage, filtered via a digital
80 * exponential filter (aka. exponential moving average, scaled):
81 * avgbat = y[n] = (N-1)/N*y[n-1] + x[n]. battery_millivolts = y[n] / N.
83 static unsigned int avgbat;
84 /* filtered battery voltage, millivolts */
85 static unsigned int battery_millivolts;
86 /* default value, mAh */
87 static int battery_capacity = BATTERY_CAPACITY_DEFAULT;
90 #if BATTERY_TYPES_COUNT > 1
91 static int battery_type = 0;
92 #else
93 #define battery_type 0
94 #endif
96 /* Power history: power_history[0] is the newest sample */
97 unsigned short power_history[POWER_HISTORY_LEN] = {0};
99 #if CONFIG_CPU == JZ4732 /* FIXME! */
100 static char power_stack[DEFAULT_STACK_SIZE + POWERMGMT_DEBUG_STACK];
101 #else
102 static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK];
103 #endif
104 static const char power_thread_name[] = "power";
106 static int poweroff_timeout = 0;
107 static int powermgmt_est_runningtime_min = -1;
109 static bool sleeptimer_active = false;
110 static long sleeptimer_endtick;
112 static long last_event_tick;
114 static int voltage_to_battery_level(int battery_millivolts);
115 static void battery_status_update(void);
116 static int runcurrent(void);
118 void battery_read_info(int *voltage, int *level)
120 int millivolts = battery_adc_voltage();
122 if (voltage)
123 *voltage = millivolts;
125 if (level)
126 *level = voltage_to_battery_level(millivolts);
129 void reset_poweroff_timer(void)
131 last_event_tick = current_tick;
134 #if BATTERY_TYPES_COUNT > 1
135 void set_battery_type(int type)
137 if (type != battery_type) {
138 if ((unsigned)type >= BATTERY_TYPES_COUNT)
139 type = 0;
141 battery_type = type;
142 battery_status_update(); /* recalculate the battery status */
145 #endif
147 void set_battery_capacity(int capacity)
149 if (capacity > BATTERY_CAPACITY_MAX)
150 capacity = BATTERY_CAPACITY_MAX;
151 if (capacity < BATTERY_CAPACITY_MIN)
152 capacity = BATTERY_CAPACITY_MIN;
154 battery_capacity = capacity;
156 battery_status_update(); /* recalculate the battery status */
159 int get_battery_capacity(void)
161 return battery_capacity;
164 int battery_time(void)
166 return powermgmt_est_runningtime_min;
169 /* Returns battery level in percent */
170 int battery_level(void)
172 #ifdef HAVE_BATTERY_SWITCH
173 if ((power_input_status() & POWER_INPUT_BATTERY) == 0)
174 return -1;
175 #endif
176 return battery_percent;
179 /* Returns filtered battery voltage [millivolts] */
180 unsigned int battery_voltage(void)
182 return battery_millivolts;
185 /* Tells if the battery level is safe for disk writes */
186 bool battery_level_safe(void)
188 #if defined(NO_LOW_BATTERY_SHUTDOWN)
189 return true;
190 #elif defined(HAVE_BATTERY_SWITCH)
191 /* Cannot rely upon the battery reading to be valid and the
192 * device could be powered externally. */
193 return input_millivolts() > battery_level_dangerous[battery_type];
194 #else
195 return battery_millivolts > battery_level_dangerous[battery_type];
196 #endif
199 void set_poweroff_timeout(int timeout)
201 poweroff_timeout = timeout;
204 void set_sleep_timer(int seconds)
206 if (seconds) {
207 sleeptimer_active = true;
208 sleeptimer_endtick = current_tick + seconds * HZ;
210 else {
211 sleeptimer_active = false;
212 sleeptimer_endtick = 0;
216 int get_sleep_timer(void)
218 if (sleeptimer_active)
219 return (sleeptimer_endtick - current_tick) / HZ;
220 else
221 return 0;
224 /* look into the percent_to_volt_* table and get a realistic battery level */
225 static int voltage_to_percent(int voltage, const short* table)
227 if (voltage <= table[0]) {
228 return 0;
230 else if (voltage >= table[10]) {
231 return 100;
233 else {
234 /* search nearest value */
235 int i = 0;
237 while (i < 10 && table[i+1] < voltage)
238 i++;
240 /* interpolate linear between the smaller and greater value */
241 /* Tens digit, 10% per entry, ones digit: interpolated */
242 return i*10 + (voltage - table[i])*10 / (table[i+1] - table[i]);
246 /* update battery level and estimated runtime, called once per minute or
247 * when battery capacity / type settings are changed */
248 static int voltage_to_battery_level(int battery_millivolts)
250 int level;
252 #if CONFIG_CHARGING >= CHARGING_MONITOR
253 if (charging_state()) {
254 /* battery level is defined to be < 100% until charging is finished */
255 level = voltage_to_percent(battery_millivolts,
256 percent_to_volt_charge);
257 if (level > 99)
258 level = 99;
260 else
261 #endif /* CONFIG_CHARGING >= CHARGING_MONITOR */
263 /* DISCHARGING or error state */
264 level = voltage_to_percent(battery_millivolts,
265 percent_to_volt_discharge[battery_type]);
268 return level;
271 static void battery_status_update(void)
273 int level = voltage_to_battery_level(battery_millivolts);
275 /* calculate estimated remaining running time */
276 #if CONFIG_CHARGING >= CHARGING_MONITOR
277 if (charging_state()) {
278 /* charging: remaining charging time */
279 powermgmt_est_runningtime_min = (100 - level)*battery_capacity*60
280 / 100 / (CURRENT_MAX_CHG - runcurrent());
282 else
283 #endif
284 /* discharging: remaining running time */
285 if (battery_millivolts > percent_to_volt_discharge[0][0]) {
286 /* linear extrapolation */
287 powermgmt_est_runningtime_min = (level + battery_percent)*60
288 * battery_capacity / 200 / runcurrent();
290 if (0 > powermgmt_est_runningtime_min) {
291 powermgmt_est_runningtime_min = 0;
294 battery_percent = level;
295 send_battery_level_event();
299 * We shut off in the following cases:
300 * 1) The unit is idle, not playing music
301 * 2) The unit is playing music, but is paused
302 * 3) The battery level has reached shutdown limit
304 * We do not shut off in the following cases:
305 * 1) The USB is connected
306 * 2) The charger is connected
307 * 3) We are recording, or recording with pause
308 * 4) The radio is playing
310 static void handle_auto_poweroff(void)
312 long timeout = poweroff_timeout*60*HZ;
313 int audio_stat = audio_status();
314 long tick = current_tick;
316 #if CONFIG_CHARGING
318 * Inhibit shutdown as long as the charger is plugged in. If it is
319 * unplugged, wait for a timeout period and then shut down.
321 if (charger_input_state == CHARGER || audio_stat == AUDIO_STATUS_PLAY) {
322 last_event_tick = current_tick;
324 #endif
326 if (!shutdown_timeout && query_force_shutdown()) {
327 backlight_on();
328 sys_poweroff();
331 if (timeout &&
332 #if CONFIG_TUNER
333 !(get_radio_status() & FMRADIO_PLAYING) &&
334 #endif
335 !usb_inserted() &&
336 (audio_stat == 0 ||
337 (audio_stat == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE) &&
338 !sleeptimer_active))) {
340 if (TIME_AFTER(tick, last_event_tick + timeout) &&
341 TIME_AFTER(tick, storage_last_disk_activity() + timeout)) {
342 sys_poweroff();
345 else if (sleeptimer_active) {
346 /* Handle sleeptimer */
347 if (TIME_AFTER(tick, sleeptimer_endtick)) {
348 audio_stop();
350 if (usb_inserted()
351 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
352 || charger_input_state != NO_CHARGER
353 #endif
355 DEBUGF("Sleep timer timeout. Stopping...\n");
356 set_sleep_timer(0);
357 backlight_off(); /* Nighty, nighty... */
359 else {
360 DEBUGF("Sleep timer timeout. Shutting off...\n");
361 sys_poweroff();
368 * Estimate how much current we are drawing just to run.
370 static int runcurrent(void)
372 int current;
374 current = CURRENT_NORMAL;
376 #ifndef BOOTLOADER
377 if (usb_inserted()
378 #ifdef HAVE_USB_POWER
379 #if (CURRENT_USB < CURRENT_NORMAL)
380 || usb_powered()
381 #else
382 && !usb_powered()
383 #endif
384 #endif
386 current = CURRENT_USB;
389 #if defined(HAVE_BACKLIGHT)
390 if (backlight_get_current_timeout() == 0) /* LED always on */
391 current += CURRENT_BACKLIGHT;
392 #endif
394 #if defined(HAVE_RECORDING) && defined(CURRENT_RECORD)
395 if (audio_status() & AUDIO_STATUS_RECORD)
396 current += CURRENT_RECORD;
397 #endif
399 #ifdef HAVE_SPDIF_POWER
400 if (spdif_powered())
401 current += CURRENT_SPDIF_OUT;
402 #endif
404 #ifdef HAVE_REMOTE_LCD
405 if (remote_detect())
406 current += CURRENT_REMOTE;
407 #endif
408 #endif /* BOOTLOADER */
410 return current;
414 /* Check to see whether or not we've received an alarm in the last second */
415 #ifdef HAVE_RTC_ALARM
416 static void power_thread_rtc_process(void)
418 if (rtc_check_alarm_flag())
419 rtc_enable_alarm(false);
421 #endif
423 /* switch off unit if battery level is too low for reliable operation */
424 bool query_force_shutdown(void)
426 #if defined(NO_LOW_BATTERY_SHUTDOWN)
427 return false;
428 #elif defined(HAVE_BATTERY_SWITCH)
429 /* Cannot rely upon the battery reading to be valid and the
430 * device could be powered externally. */
431 return input_millivolts() < battery_level_shutoff[battery_type];
432 #else
433 return battery_millivolts < battery_level_shutoff[battery_type];
434 #endif
437 #if defined(HAVE_BATTERY_SWITCH) || defined(HAVE_RESET_BATTERY_FILTER)
439 * Reset the battery voltage filter to a new value and update the
440 * status.
442 void reset_battery_filter(int millivolts)
444 avgbat = millivolts * BATT_AVE_SAMPLES;
445 battery_millivolts = millivolts;
446 battery_status_update();
448 #endif /* HAVE_BATTERY_SWITCH */
450 /** Generic charging algorithms for common charging types **/
451 #if CONFIG_CHARGING == 0 || CONFIG_CHARGING == CHARGING_SIMPLE
452 static inline void powermgmt_init_target(void)
454 /* Nothing to do */
457 static inline void charging_algorithm_step(void)
459 /* Nothing to do */
462 static inline void charging_algorithm_close(void)
464 /* Nothing to do */
466 #elif CONFIG_CHARGING == CHARGING_MONITOR
468 * Monitor CHARGING/DISCHARGING state.
470 static inline void powermgmt_init_target(void)
472 /* Nothing to do */
475 static inline void charging_algorithm_step(void)
477 switch (charger_input_state)
479 case CHARGER_PLUGGED:
480 case CHARGER:
481 if (charging_state()) {
482 charge_state = CHARGING;
483 break;
485 /* Fallthrough */
486 case CHARGER_UNPLUGGED:
487 case NO_CHARGER:
488 charge_state = DISCHARGING;
489 break;
493 static inline void charging_algorithm_close(void)
495 /* Nothing to do */
497 #endif /* CONFIG_CHARGING == * */
499 #if CONFIG_CHARGING
500 /* Shortcut function calls - compatibility, simplicity. */
502 /* Returns true if any power input is capable of charging. */
503 bool charger_inserted(void)
505 return power_thread_inputs & POWER_INPUT_CHARGER;
508 /* Returns true if any power input is connected - charging-capable
509 * or not. */
510 bool power_input_present(void)
512 return power_thread_inputs & POWER_INPUT;
516 * Detect charger inserted. Return true if the state is transistional.
518 static inline bool detect_charger(unsigned int pwr)
521 * Detect charger plugged/unplugged transitions. On a plugged or
522 * unplugged event, we return immediately, run once through the main
523 * loop (including the subroutines), and end up back here where we
524 * transition to the appropriate steady state charger on/off state.
526 if (pwr & POWER_INPUT_CHARGER) {
527 switch (charger_input_state)
529 case NO_CHARGER:
530 case CHARGER_UNPLUGGED:
531 charger_input_state = CHARGER_PLUGGED;
532 break;
534 case CHARGER_PLUGGED:
535 queue_broadcast(SYS_CHARGER_CONNECTED, 0);
536 last_sent_battery_level = 0;
537 charger_input_state = CHARGER;
538 break;
540 case CHARGER:
541 /* Steady state */
542 return false;
545 else { /* charger not inserted */
546 switch (charger_input_state)
548 case NO_CHARGER:
549 /* Steady state */
550 return false;
552 case CHARGER_UNPLUGGED:
553 queue_broadcast(SYS_CHARGER_DISCONNECTED, 0);
554 last_sent_battery_level = 100;
555 charger_input_state = NO_CHARGER;
556 break;
558 case CHARGER_PLUGGED:
559 case CHARGER:
560 charger_input_state = CHARGER_UNPLUGGED;
561 break;
565 /* Transitional state */
566 return true;
568 #endif /* CONFIG_CHARGING */
571 * Monitor the presence of a charger and perform critical frequent steps
572 * such as running the battery voltage filter.
574 static inline void power_thread_step(void)
576 /* If the power off timeout expires, the main thread has failed
577 to shut down the system, and we need to force a power off */
578 if (shutdown_timeout) {
579 shutdown_timeout -= POWER_THREAD_STEP_TICKS;
581 if (shutdown_timeout <= 0)
582 power_off();
585 #ifdef HAVE_RTC_ALARM
586 power_thread_rtc_process();
587 #endif
590 * Do a digital exponential filter. We don't sample the battery if
591 * the disk is spinning unless we are in USB mode (the disk will most
592 * likely always be spinning in USB mode) or charging.
594 if (!storage_disk_is_active() || usb_inserted()
595 #if CONFIG_CHARGING >= CHARGING_MONITOR
596 || charger_input_state == CHARGER
597 #endif
599 avgbat += battery_adc_voltage() - avgbat / BATT_AVE_SAMPLES;
601 * battery_millivolts is the millivolt-scaled filtered battery value.
603 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
605 /* update battery status every time an update is available */
606 battery_status_update();
608 else if (battery_percent < 8) {
610 * If battery is low, observe voltage during disk activity.
611 * Shut down if voltage drops below shutoff level and we are not
612 * using NiMH or Alkaline batteries.
614 battery_millivolts = (battery_adc_voltage() +
615 battery_millivolts + 1) / 2;
617 /* update battery status every time an update is available */
618 battery_status_update();
620 if (!shutdown_timeout && query_force_shutdown()) {
621 sys_poweroff();
623 else {
624 avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES;
627 } /* power_thread_step */
629 static void power_thread(void)
631 long next_power_hist;
633 /* Delay reading the first battery level */
634 #ifdef MROBE_100
635 while (battery_adc_voltage() > 4200) /* gives false readings initially */
636 #endif
638 sleep(HZ/100);
641 #if CONFIG_CHARGING
642 /* Initialize power input status before calling other routines. */
643 power_thread_inputs = power_input_status();
644 #endif
646 /* initialize the voltages for the exponential filter */
647 avgbat = battery_adc_voltage() + 15;
649 #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */
650 /* The battery voltage is usually a little lower directly after
651 turning on, because the disk was used heavily. Raise it by 5% */
652 #if CONFIG_CHARGING
653 if (!charger_inserted()) /* only if charger not connected */
654 #endif
656 avgbat += (percent_to_volt_discharge[battery_type][6] -
657 percent_to_volt_discharge[battery_type][5]) / 2;
659 #endif /* HAVE_DISK_STORAGE */
661 avgbat = avgbat * BATT_AVE_SAMPLES;
662 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
663 power_history[0] = battery_millivolts;
665 #if CONFIG_CHARGING
666 if (charger_inserted()) {
667 battery_percent = voltage_to_percent(battery_millivolts,
668 percent_to_volt_charge);
670 else
671 #endif
673 battery_percent = voltage_to_percent(battery_millivolts,
674 percent_to_volt_discharge[battery_type]);
675 battery_percent += battery_percent < 100;
678 powermgmt_init_target();
680 next_power_hist = current_tick + HZ*60;
682 while (1)
684 #if CONFIG_CHARGING
685 unsigned int pwr = power_input_status();
686 #ifdef HAVE_BATTERY_SWITCH
687 if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) {
688 sleep(HZ/10);
689 reset_battery_filter(battery_adc_voltage());
691 #endif
692 power_thread_inputs = pwr;
694 if (!detect_charger(pwr))
695 #endif /* CONFIG_CHARGING */
697 /* Steady state */
698 sleep(POWER_THREAD_STEP_TICKS);
700 /* Do common power tasks */
701 power_thread_step();
704 /* Perform target tasks */
705 charging_algorithm_step();
707 if (TIME_BEFORE(current_tick, next_power_hist))
708 continue;
710 /* increment to ensure there is a record for every minute
711 * rather than go forward from the current tick */
712 next_power_hist += HZ*60;
714 /* rotate the power history */
715 memmove(&power_history[1], &power_history[0],
716 sizeof(power_history) - sizeof(power_history[0]));
718 /* insert new value at the start, in millivolts 8-) */
719 power_history[0] = battery_millivolts;
721 handle_auto_poweroff();
723 } /* power_thread */
725 void powermgmt_init(void)
727 create_thread(power_thread, power_stack, sizeof(power_stack), 0,
728 power_thread_name IF_PRIO(, PRIORITY_SYSTEM)
729 IF_COP(, CPU));
732 /* Various hardware housekeeping tasks relating to shutting down the player */
733 void shutdown_hw(void)
735 charging_algorithm_close();
736 audio_stop();
738 if (battery_level_safe()) { /* do not save on critical battery */
739 #ifdef HAVE_LCD_BITMAP
740 glyph_cache_save(NULL);
741 #endif
743 /* Commit pending writes if needed. Even though we don't do write caching,
744 things like flash translation layers may need this to commit scattered
745 pages to there final locations. So far only used for iPod Nano 2G. */
746 #ifdef HAVE_STORAGE_FLUSH
747 storage_flush();
748 #endif
750 if (storage_disk_is_active())
751 storage_spindown(1);
754 while (storage_disk_is_active())
755 sleep(HZ/10);
757 #if CONFIG_CODEC == SWCODEC
758 audiohw_close();
759 #else
760 mp3_shutdown();
761 #endif
763 /* If HD is still active we try to wait for spindown, otherwise the
764 shutdown_timeout in power_thread_step will force a power off */
765 while (storage_disk_is_active())
766 sleep(HZ/10);
768 #ifndef HAVE_LCD_COLOR
769 lcd_set_contrast(0);
770 #endif
771 #ifdef HAVE_REMOTE_LCD
772 lcd_remote_set_contrast(0);
773 #endif
774 #ifdef HAVE_LCD_SHUTDOWN
775 lcd_shutdown();
776 #endif
778 /* Small delay to make sure all HW gets time to flush. Especially
779 eeprom chips are quite slow and might be still writing the last
780 byte. */
781 sleep(HZ/4);
782 power_off();
785 void sys_poweroff(void)
787 #ifndef BOOTLOADER
788 logf("sys_poweroff()");
789 /* If the main thread fails to shut down the system, we will force a
790 power off after an 20 second timeout - 28 seconds if recording */
791 if (shutdown_timeout == 0) {
792 #if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)
793 pcf50606_reset_timeout(); /* Reset timer on first attempt only */
794 #endif
795 #ifdef HAVE_RECORDING
796 if (audio_status() & AUDIO_STATUS_RECORD)
797 shutdown_timeout += HZ*8;
798 #endif
799 #ifdef IPOD_NANO2G
800 /* The FTL alone may take half a minute to shut down cleanly. */
801 shutdown_timeout += HZ*60;
802 #else
803 shutdown_timeout += HZ*20;
804 #endif
807 queue_broadcast(SYS_POWEROFF, 0);
808 #endif /* BOOTLOADER */
811 void cancel_shutdown(void)
813 logf("cancel_shutdown()");
815 #if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)
816 /* TODO: Move some things to target/ tree */
817 if (shutdown_timeout)
818 pcf50606_reset_timeout();
819 #endif
821 shutdown_timeout = 0;
823 #endif /* SIMULATOR */
825 /* Send system battery level update events on reaching certain significant
826 levels. This must be called after battery_percent has been updated. */
827 void send_battery_level_event(void)
829 static const int levels[] = { 5, 15, 30, 50, 0 };
830 const int *level = levels;
832 while (*level)
834 if (battery_percent <= *level && last_sent_battery_level > *level) {
835 last_sent_battery_level = *level;
836 queue_broadcast(SYS_BATTERY_UPDATE, last_sent_battery_level);
837 break;
840 level++;