imx233: modify arm cache timings on frequency switch
[maemo-rb.git] / firmware / powermgmt.c
blobb6d4b9f66ef8f470b69ac6a0acedbbfaf8a0211d
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 #ifdef HAVE_REMOTE_LCD
47 #include "lcd-remote.h"
48 #endif
49 #if (CONFIG_PLATFORM & PLATFORM_HOSTED)
50 #include <time.h>
51 #endif
53 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) \
54 && !defined (SIMULATOR)
55 #include "pcf50606.h"
56 #endif
58 /** Shared by sim **/
59 int last_sent_battery_level = 100;
60 /* battery level (0-100%) */
61 int battery_percent = -1;
62 void send_battery_level_event(void);
63 static void set_sleep_timer(int seconds);
65 static bool sleeptimer_active = false;
66 static long sleeptimer_endtick;
67 /* Whether an active sleep timer should be restarted when a key is pressed */
68 static bool sleeptimer_key_restarts = false;
69 /* The number of seconds the sleep timer was last set to */
70 static unsigned int sleeptimer_duration = 0;
72 #if CONFIG_CHARGING
73 /* State of the charger input as seen by the power thread */
74 enum charger_input_state_type charger_input_state;
75 /* Power inputs as seen by the power thread */
76 unsigned int power_thread_inputs;
77 #if CONFIG_CHARGING >= CHARGING_MONITOR
78 /* Charging state (mode) as seen by the power thread */
79 enum charge_state_type charge_state = DISCHARGING;
80 #endif
81 #endif /* CONFIG_CHARGING */
83 static int shutdown_timeout = 0;
85 void handle_auto_poweroff(void);
86 static int poweroff_timeout = 0;
87 static long last_event_tick = 0;
89 #if (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) == PERCENTAGE_MEASURE
90 int _battery_voltage(void) { return -1; }
92 const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
93 const unsigned short percent_to_volt_charge[11];
95 #elif (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE) == VOLTAGE_MEASURE
96 int _battery_level(void) { return -1; }
98 * Average battery voltage and charger voltage, filtered via a digital
99 * exponential filter (aka. exponential moving average, scaled):
100 * avgbat = y[n] = (N-1)/N*y[n-1] + x[n]. battery_millivolts = y[n] / N.
102 static unsigned int avgbat;
103 /* filtered battery voltage, 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; }
109 const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
110 const unsigned short percent_to_volt_charge[11];
111 #endif
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
118 /* default value, mAh */
119 static int battery_capacity = BATTERY_CAPACITY_DEFAULT;
121 #if BATTERY_TYPES_COUNT > 1
122 static int battery_type = 0;
123 #else
124 #define battery_type 0
125 #endif
127 /* Power history: power_history[0] is the newest sample */
128 unsigned short power_history[POWER_HISTORY_LEN] = {0};
130 #if CONFIG_CPU == JZ4732 /* FIXME! */ || (CONFIG_PLATFORM & PLATFORM_HOSTED)
131 static char power_stack[DEFAULT_STACK_SIZE + POWERMGMT_DEBUG_STACK];
132 #else
133 static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK];
134 #endif
135 static const char power_thread_name[] = "power";
138 static int voltage_to_battery_level(int battery_millivolts);
139 static void battery_status_update(void);
141 #ifdef CURRENT_NORMAL /*only used if we have run current*/
142 static int runcurrent(void);
143 #endif
145 void battery_read_info(int *voltage, int *level)
147 int millivolts = _battery_voltage();
148 int percent;
150 if (voltage)
151 *voltage = millivolts;
153 if (level) {
154 percent = voltage_to_battery_level(millivolts);
155 if (percent < 0)
156 percent = _battery_level();
157 *level = percent;
161 #if BATTERY_TYPES_COUNT > 1
162 void set_battery_type(int type)
164 if (type != battery_type) {
165 if ((unsigned)type >= BATTERY_TYPES_COUNT)
166 type = 0;
168 battery_type = type;
169 battery_status_update(); /* recalculate the battery status */
172 #endif
174 #ifdef BATTERY_CAPACITY_MIN
175 void set_battery_capacity(int capacity)
177 if (capacity > BATTERY_CAPACITY_MAX)
178 capacity = BATTERY_CAPACITY_MAX;
179 if (capacity < BATTERY_CAPACITY_MIN)
180 capacity = BATTERY_CAPACITY_MIN;
182 battery_capacity = capacity;
184 battery_status_update(); /* recalculate the battery status */
186 #endif
188 int get_battery_capacity(void)
190 return battery_capacity;
193 int battery_time(void)
195 #if ((CONFIG_BATTERY_MEASURE & TIME_MEASURE) == 0)
197 #ifndef CURRENT_NORMAL /* no estimation without current */
198 return -1;
199 #endif
200 if (battery_capacity <= 0) /* nor without capacity */
201 return -1;
203 #endif
204 return _battery_time();
207 /* Returns battery level in percent */
208 int battery_level(void)
210 #ifdef HAVE_BATTERY_SWITCH
211 if ((power_input_status() & POWER_INPUT_BATTERY) == 0)
212 return -1;
213 #endif
214 return battery_percent;
217 /* Tells if the battery level is safe for disk writes */
218 bool battery_level_safe(void)
220 #if defined(NO_LOW_BATTERY_SHUTDOWN)
221 return true;
222 #elif (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE)
223 return (battery_percent > 0);
224 #elif defined(HAVE_BATTERY_SWITCH)
225 /* Cannot rely upon the battery reading to be valid and the
226 * device could be powered externally. */
227 return input_millivolts() > battery_level_dangerous[battery_type];
228 #else
229 return battery_millivolts > battery_level_dangerous[battery_type];
230 #endif
233 /* look into the percent_to_volt_* table and get a realistic battery level */
234 static int voltage_to_percent(int voltage, const short* table)
236 if (voltage <= table[0]) {
237 return 0;
239 else if (voltage >= table[10]) {
240 return 100;
242 else {
243 /* search nearest value */
244 int i = 0;
246 while (i < 10 && table[i+1] < voltage)
247 i++;
249 /* interpolate linear between the smaller and greater value */
250 /* Tens digit, 10% per entry, ones digit: interpolated */
251 return i*10 + (voltage - table[i])*10 / (table[i+1] - table[i]);
255 /* update battery level and estimated runtime, called once per minute or
256 * when battery capacity / type settings are changed */
257 static int voltage_to_battery_level(int battery_millivolts)
259 int level;
261 if (battery_millivolts < 0)
262 return -1;
264 #if CONFIG_CHARGING >= CHARGING_MONITOR
265 if (charging_state()) {
266 /* battery level is defined to be < 100% until charging is finished */
267 level = voltage_to_percent(battery_millivolts,
268 percent_to_volt_charge);
269 if (level > 99)
270 level = 99;
272 else
273 #endif /* CONFIG_CHARGING >= CHARGING_MONITOR */
275 /* DISCHARGING or error state */
276 level = voltage_to_percent(battery_millivolts,
277 percent_to_volt_discharge[battery_type]);
280 return level;
283 static void battery_status_update(void)
285 int millivolt = battery_voltage();
286 int level = _battery_level();
288 if (level < 0)
289 level = voltage_to_battery_level(millivolt);
291 #ifdef CURRENT_NORMAL /*don't try to estimate run or charge
292 time without normal current defined*/
293 /* calculate estimated remaining running time */
294 #if CONFIG_CHARGING >= CHARGING_MONITOR
295 if (charging_state()) {
296 /* charging: remaining charging time */
297 powermgmt_est_runningtime_min = (100 - level)*battery_capacity*60
298 / 100 / (CURRENT_MAX_CHG - runcurrent());
300 else
301 #endif
303 /* discharging: remaining running time */
304 if (level > 0 && (millivolt > percent_to_volt_discharge[battery_type][0]
305 || millivolt < 0)) {
306 /* linear extrapolation */
307 powermgmt_est_runningtime_min = (level + battery_percent)*60
308 * battery_capacity / 200 / runcurrent();
310 if (0 > powermgmt_est_runningtime_min) {
311 powermgmt_est_runningtime_min = 0;
313 #endif
315 battery_percent = level;
316 send_battery_level_event();
319 #ifdef CURRENT_NORMAL /*check that we have a current defined in a config file*/
322 * Estimate how much current we are drawing just to run.
324 static int runcurrent(void)
326 int current = CURRENT_NORMAL;
328 #ifndef BOOTLOADER
329 if (usb_inserted()
330 #ifdef HAVE_USB_POWER
331 #if (CURRENT_USB < CURRENT_NORMAL)
332 || usb_powered()
333 #else
334 && !usb_powered()
335 #endif
336 #endif
338 current = CURRENT_USB;
341 #if defined(HAVE_BACKLIGHT)
342 if (backlight_get_current_timeout() == 0) /* LED always on */
343 current += CURRENT_BACKLIGHT;
344 #endif
346 #if defined(HAVE_RECORDING) && defined(CURRENT_RECORD)
347 if (audio_status() & AUDIO_STATUS_RECORD)
348 current += CURRENT_RECORD;
349 #endif
351 #ifdef HAVE_SPDIF_POWER
352 if (spdif_powered())
353 current += CURRENT_SPDIF_OUT;
354 #endif
356 #ifdef HAVE_REMOTE_LCD
357 if (remote_detect())
358 current += CURRENT_REMOTE;
359 #endif
361 #if defined(HAVE_ATA_POWER_OFF) && defined(CURRENT_ATA)
362 if (ide_powered())
363 current += CURRENT_ATA;
364 #endif
366 #endif /* BOOTLOADER */
368 return current;
371 #endif /* CURRENT_NORMAL */
373 /* Check to see whether or not we've received an alarm in the last second */
374 #ifdef HAVE_RTC_ALARM
375 static void power_thread_rtc_process(void)
377 if (rtc_check_alarm_flag())
378 rtc_enable_alarm(false);
380 #endif
382 /* switch off unit if battery level is too low for reliable operation */
383 bool query_force_shutdown(void)
385 #if defined(NO_LOW_BATTERY_SHUTDOWN)
386 return false;
387 #elif CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE
388 return battery_percent == 0;
389 #elif defined(HAVE_BATTERY_SWITCH)
390 /* Cannot rely upon the battery reading to be valid and the
391 * device could be powered externally. */
392 return input_millivolts() < battery_level_shutoff[battery_type];
393 #else
394 return battery_millivolts < battery_level_shutoff[battery_type];
395 #endif
398 #if defined(HAVE_BATTERY_SWITCH) || defined(HAVE_RESET_BATTERY_FILTER)
400 * Reset the battery voltage filter to a new value and update the
401 * status.
403 void reset_battery_filter(int millivolts)
405 avgbat = millivolts * BATT_AVE_SAMPLES;
406 battery_millivolts = millivolts;
407 battery_status_update();
409 #endif /* HAVE_BATTERY_SWITCH */
411 /** Generic charging algorithms for common charging types **/
412 #if CONFIG_CHARGING == 0 || CONFIG_CHARGING == CHARGING_SIMPLE
413 static inline void powermgmt_init_target(void)
415 /* Nothing to do */
418 static inline void charging_algorithm_step(void)
420 /* Nothing to do */
423 static inline void charging_algorithm_close(void)
425 /* Nothing to do */
427 #elif CONFIG_CHARGING == CHARGING_MONITOR
429 * Monitor CHARGING/DISCHARGING state.
431 static inline void powermgmt_init_target(void)
433 /* Nothing to do */
436 static inline void charging_algorithm_step(void)
438 switch (charger_input_state)
440 case CHARGER_PLUGGED:
441 case CHARGER:
442 if (charging_state()) {
443 charge_state = CHARGING;
444 break;
446 /* Fallthrough */
447 case CHARGER_UNPLUGGED:
448 case NO_CHARGER:
449 charge_state = DISCHARGING;
450 break;
454 static inline void charging_algorithm_close(void)
456 /* Nothing to do */
458 #endif /* CONFIG_CHARGING == * */
460 #if CONFIG_CHARGING
461 /* Shortcut function calls - compatibility, simplicity. */
463 /* Returns true if any power input is capable of charging. */
464 bool charger_inserted(void)
466 return power_thread_inputs & POWER_INPUT_CHARGER;
469 /* Returns true if any power input is connected - charging-capable
470 * or not. */
471 bool power_input_present(void)
473 return power_thread_inputs & POWER_INPUT;
477 * Detect charger inserted. Return true if the state is transistional.
479 static inline bool detect_charger(unsigned int pwr)
482 * Detect charger plugged/unplugged transitions. On a plugged or
483 * unplugged event, we return immediately, run once through the main
484 * loop (including the subroutines), and end up back here where we
485 * transition to the appropriate steady state charger on/off state.
487 if (pwr & POWER_INPUT_CHARGER) {
488 switch (charger_input_state)
490 case NO_CHARGER:
491 case CHARGER_UNPLUGGED:
492 charger_input_state = CHARGER_PLUGGED;
493 break;
495 case CHARGER_PLUGGED:
496 queue_broadcast(SYS_CHARGER_CONNECTED, 0);
497 last_sent_battery_level = 0;
498 charger_input_state = CHARGER;
499 break;
501 case CHARGER:
502 /* Steady state */
503 return false;
506 else { /* charger not inserted */
507 switch (charger_input_state)
509 case NO_CHARGER:
510 /* Steady state */
511 return false;
513 case CHARGER_UNPLUGGED:
514 queue_broadcast(SYS_CHARGER_DISCONNECTED, 0);
515 last_sent_battery_level = 100;
516 charger_input_state = NO_CHARGER;
517 break;
519 case CHARGER_PLUGGED:
520 case CHARGER:
521 charger_input_state = CHARGER_UNPLUGGED;
522 break;
526 /* Transitional state */
527 return true;
529 #endif /* CONFIG_CHARGING */
532 #if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE
533 /* Returns filtered battery voltage [millivolts] */
534 int battery_voltage(void)
536 return battery_millivolts;
539 static void average_init(void)
541 /* initialize the voltages for the exponential filter */
542 avgbat = _battery_voltage() + 15;
544 #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */
545 /* The battery voltage is usually a little lower directly after
546 turning on, because the disk was used heavily. Raise it by 5% */
547 #if CONFIG_CHARGING
548 if (!charger_inserted()) /* only if charger not connected */
549 #endif
551 avgbat += (percent_to_volt_discharge[battery_type][6] -
552 percent_to_volt_discharge[battery_type][5]) / 2;
554 #endif /* HAVE_DISK_STORAGE */
556 avgbat = avgbat * BATT_AVE_SAMPLES;
557 battery_millivolts = power_history[0] = avgbat / BATT_AVE_SAMPLES;
560 static void average_step(void)
562 avgbat += _battery_voltage() - avgbat / BATT_AVE_SAMPLES;
564 * battery_millivolts is the millivolt-scaled filtered battery value.
566 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
569 static void average_step_low(void)
571 battery_millivolts = (_battery_voltage() + battery_millivolts + 1) / 2;
572 avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES;
575 static void init_battery_percent(void)
577 #if CONFIG_CHARGING
578 if (charger_inserted()) {
579 battery_percent = voltage_to_percent(battery_millivolts,
580 percent_to_volt_charge);
582 else
583 #endif
585 battery_percent = voltage_to_percent(battery_millivolts,
586 percent_to_volt_discharge[battery_type]);
587 battery_percent += battery_percent < 100;
592 static int power_hist_item(void)
594 return battery_millivolts;
596 #define power_history_unit() battery_millivolts
598 #else
599 int battery_voltage(void)
601 return -1;
604 static void average_init(void) {}
605 static void average_step(void) {}
606 static void average_step_low(void) {}
607 static void init_battery_percent(void)
609 battery_percent = _battery_level();
612 static int power_hist_item(void)
614 return battery_percent;
616 #endif
618 static void collect_power_history(void)
620 /* rotate the power history */
621 memmove(&power_history[1], &power_history[0],
622 sizeof(power_history) - sizeof(power_history[0]));
623 power_history[0] = power_hist_item();
627 * Monitor the presence of a charger and perform critical frequent steps
628 * such as running the battery voltage filter.
630 static inline void power_thread_step(void)
632 /* If the power off timeout expires, the main thread has failed
633 to shut down the system, and we need to force a power off */
634 if (shutdown_timeout) {
635 shutdown_timeout -= POWER_THREAD_STEP_TICKS;
637 if (shutdown_timeout <= 0)
638 power_off();
641 #ifdef HAVE_RTC_ALARM
642 power_thread_rtc_process();
643 #endif
646 * Do a digital exponential filter. We don't sample the battery if
647 * the disk is spinning unless we are in USB mode (the disk will most
648 * likely always be spinning in USB mode) or charging.
650 if (!storage_disk_is_active() || usb_inserted()
651 #if CONFIG_CHARGING >= CHARGING_MONITOR
652 || charger_input_state == CHARGER
653 #endif
655 average_step();
656 /* update battery status every time an update is available */
657 battery_status_update();
659 else if (battery_percent < 8) {
660 average_step_low();
661 /* update battery status every time an update is available */
662 battery_status_update();
665 * If battery is low, observe voltage during disk activity.
666 * Shut down if voltage drops below shutoff level and we are not
667 * using NiMH or Alkaline batteries.
669 if (!shutdown_timeout && query_force_shutdown()) {
670 sys_poweroff();
673 } /* power_thread_step */
675 static void power_thread(void)
677 long next_power_hist;
679 /* Delay reading the first battery level */
680 #ifdef MROBE_100
681 while (_battery_voltage() > 4200) /* gives false readings initially */
682 #endif
684 sleep(HZ/100);
687 #if CONFIG_CHARGING
688 /* Initialize power input status before calling other routines. */
689 power_thread_inputs = power_input_status();
690 #endif
692 /* initialize voltage averaging (if available) */
693 average_init();
694 /* get initial battery level value (in %) */
695 init_battery_percent();
696 /* get some initial data for the power curve */
697 collect_power_history();
698 /* call target specific init now */
699 powermgmt_init_target();
701 next_power_hist = current_tick + HZ*60;
703 while (1)
705 #if CONFIG_CHARGING
706 unsigned int pwr = power_input_status();
707 #ifdef HAVE_BATTERY_SWITCH
708 if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) {
709 sleep(HZ/10);
710 reset_battery_filter(_battery_voltage());
712 #endif
713 power_thread_inputs = pwr;
715 if (!detect_charger(pwr))
716 #endif /* CONFIG_CHARGING */
718 /* Steady state */
719 sleep(POWER_THREAD_STEP_TICKS);
721 /* Do common power tasks */
722 power_thread_step();
725 /* Perform target tasks */
726 charging_algorithm_step();
728 /* check if some idle or sleep timer wears off */
729 handle_auto_poweroff();
731 if (TIME_AFTER(current_tick, next_power_hist)) {
732 /* increment to ensure there is a record for every minute
733 * rather than go forward from the current tick */
734 next_power_hist += HZ*60;
735 collect_power_history();
738 } /* power_thread */
740 void powermgmt_init(void)
742 create_thread(power_thread, power_stack, sizeof(power_stack), 0,
743 power_thread_name IF_PRIO(, PRIORITY_SYSTEM)
744 IF_COP(, CPU));
747 /* Various hardware housekeeping tasks relating to shutting down the player */
748 void shutdown_hw(void)
750 charging_algorithm_close();
751 audio_stop();
753 if (battery_level_safe()) { /* do not save on critical battery */
754 #ifdef HAVE_LCD_BITMAP
755 font_unload_all();
756 #endif
758 /* Commit pending writes if needed. Even though we don't do write caching,
759 things like flash translation layers may need this to commit scattered
760 pages to there final locations. So far only used for iPod Nano 2G. */
761 #ifdef HAVE_STORAGE_FLUSH
762 storage_flush();
763 #endif
765 if (storage_disk_is_active())
766 storage_spindown(1);
769 #if CONFIG_CODEC == SWCODEC
770 audiohw_close();
771 #else
772 mp3_shutdown();
773 #endif
775 /* If HD is still active we try to wait for spindown, otherwise the
776 shutdown_timeout in power_thread_step will force a power off */
777 while (storage_disk_is_active())
778 sleep(HZ/10);
780 #ifndef HAVE_LCD_COLOR
781 lcd_set_contrast(0);
782 #endif
783 #ifdef HAVE_REMOTE_LCD
784 lcd_remote_set_contrast(0);
785 #endif
786 #ifdef HAVE_LCD_SHUTDOWN
787 lcd_shutdown();
788 #endif
790 /* Small delay to make sure all HW gets time to flush. Especially
791 eeprom chips are quite slow and might be still writing the last
792 byte. */
793 sleep(HZ/4);
794 power_off();
797 void set_poweroff_timeout(int timeout)
799 poweroff_timeout = timeout;
802 void reset_poweroff_timer(void)
804 last_event_tick = current_tick;
805 if (sleeptimer_active && sleeptimer_key_restarts)
806 set_sleep_timer(sleeptimer_duration);
809 void sys_poweroff(void)
811 #ifndef BOOTLOADER
812 logf("sys_poweroff()");
813 /* If the main thread fails to shut down the system, we will force a
814 power off after an 20 second timeout - 28 seconds if recording */
815 if (shutdown_timeout == 0) {
816 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) && !defined(SIMULATOR)
817 pcf50606_reset_timeout(); /* Reset timer on first attempt only */
818 #endif
819 #ifdef HAVE_RECORDING
820 if (audio_status() & AUDIO_STATUS_RECORD)
821 shutdown_timeout += HZ*8;
822 #endif
823 #ifdef IPOD_NANO2G
824 /* The FTL alone may take half a minute to shut down cleanly. */
825 shutdown_timeout += HZ*60;
826 #else
827 shutdown_timeout += HZ*20;
828 #endif
831 queue_broadcast(SYS_POWEROFF, 0);
832 #endif /* BOOTLOADER */
835 void cancel_shutdown(void)
837 logf("cancel_shutdown()");
839 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) && !defined(SIMULATOR)
840 /* TODO: Move some things to target/ tree */
841 if (shutdown_timeout)
842 pcf50606_reset_timeout();
843 #endif
845 shutdown_timeout = 0;
848 /* Send system battery level update events on reaching certain significant
849 levels. This must be called after battery_percent has been updated. */
850 void send_battery_level_event(void)
852 static const int levels[] = { 5, 15, 30, 50, 0 };
853 const int *level = levels;
855 while (*level)
857 if (battery_percent <= *level && last_sent_battery_level > *level) {
858 last_sent_battery_level = *level;
859 queue_broadcast(SYS_BATTERY_UPDATE, last_sent_battery_level);
860 break;
863 level++;
867 void set_sleeptimer_duration(int minutes)
869 set_sleep_timer(minutes * 60);
872 static void set_sleep_timer(int seconds)
874 if (seconds) {
875 sleeptimer_active = true;
876 sleeptimer_endtick = current_tick + seconds * HZ;
878 else {
879 sleeptimer_active = false;
880 sleeptimer_endtick = 0;
882 sleeptimer_duration = seconds;
885 int get_sleep_timer(void)
887 if (sleeptimer_active && (sleeptimer_endtick >= current_tick))
888 return (sleeptimer_endtick - current_tick) / HZ;
889 else
890 return 0;
893 void set_keypress_restarts_sleep_timer(bool enable)
895 sleeptimer_key_restarts = enable;
898 #ifndef BOOTLOADER
899 static void handle_sleep_timer(void)
901 if (!sleeptimer_active)
902 return;
904 /* Handle sleeptimer */
905 if (TIME_AFTER(current_tick, sleeptimer_endtick)) {
906 if (usb_inserted()
907 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
908 || charger_input_state != NO_CHARGER
909 #endif
911 DEBUGF("Sleep timer timeout. Stopping...\n");
912 audio_pause();
913 set_sleep_timer(0);
914 backlight_off(); /* Nighty, nighty... */
916 else {
917 DEBUGF("Sleep timer timeout. Shutting off...\n");
918 sys_poweroff();
922 #endif /* BOOTLOADER */
925 * We shut off in the following cases:
926 * 1) The unit is idle, not playing music
927 * 2) The unit is playing music, but is paused
928 * 3) The battery level has reached shutdown limit
930 * We do not shut off in the following cases:
931 * 1) The USB is connected
932 * 2) The charger is connected
933 * 3) We are recording, or recording with pause
934 * 4) The radio is playing
936 void handle_auto_poweroff(void)
938 #ifndef BOOTLOADER
939 long timeout = poweroff_timeout*60*HZ;
940 int audio_stat = audio_status();
941 long tick = current_tick;
944 * Inhibit shutdown as long as the charger is plugged in. If it is
945 * unplugged, wait for a timeout period and then shut down.
947 if (audio_stat == AUDIO_STATUS_PLAY
948 #if CONFIG_CHARGING
949 || charger_input_state == CHARGER
950 #endif
952 last_event_tick = current_tick;
955 if (!shutdown_timeout && query_force_shutdown()) {
956 backlight_on();
957 sys_poweroff();
960 if (timeout &&
961 #if CONFIG_TUNER
962 !(get_radio_status() & FMRADIO_PLAYING) &&
963 #endif
964 !usb_inserted() &&
965 (audio_stat == 0 ||
966 (audio_stat == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE) &&
967 !sleeptimer_active))) {
969 if (TIME_AFTER(tick, last_event_tick + timeout)
970 #if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
971 && TIME_AFTER(tick, storage_last_disk_activity() + timeout)
972 #endif
974 sys_poweroff();
976 } else
977 handle_sleep_timer();
978 #endif