1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
32 #include "mp3_playback.h"
34 #include "powermgmt.h"
35 #include "backlight.h"
42 #ifdef HAVE_LCD_BITMAP
46 #include "lcd-remote.h"
47 #if (CONFIG_PLATFORM & PLATFORM_HOSTED)
51 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5)) && !defined (SIMULATOR)
52 #include "lcd-remote-target.h"
54 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) \
55 && !defined (SIMULATOR)
60 int last_sent_battery_level
= 100;
61 /* battery level (0-100%) */
62 int battery_percent
= -1;
63 void send_battery_level_event(void);
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
;
74 #endif /* CONFIG_CHARGING */
76 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
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;
93 #define battery_type 0
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
];
102 static char power_stack
[DEFAULT_STACK_SIZE
/2 + POWERMGMT_DEBUG_STACK
];
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);
117 #ifdef CURRENT_NORMAL /*only used if we have run current*/
118 static int runcurrent(void);
121 void battery_read_info(int *voltage
, int *level
)
123 int millivolts
= battery_adc_voltage();
126 *voltage
= millivolts
;
129 *level
= voltage_to_battery_level(millivolts
);
132 void reset_poweroff_timer(void)
134 last_event_tick
= current_tick
;
137 #if BATTERY_TYPES_COUNT > 1
138 void set_battery_type(int type
)
140 if (type
!= battery_type
) {
141 if ((unsigned)type
>= BATTERY_TYPES_COUNT
)
145 battery_status_update(); /* recalculate the battery status */
150 void set_battery_capacity(int capacity
)
152 if (capacity
> BATTERY_CAPACITY_MAX
)
153 capacity
= BATTERY_CAPACITY_MAX
;
154 if (capacity
< BATTERY_CAPACITY_MIN
)
155 capacity
= BATTERY_CAPACITY_MIN
;
157 battery_capacity
= capacity
;
159 battery_status_update(); /* recalculate the battery status */
162 int get_battery_capacity(void)
164 return battery_capacity
;
167 int battery_time(void)
169 return powermgmt_est_runningtime_min
;
172 /* Returns battery level in percent */
173 int battery_level(void)
175 #ifdef HAVE_BATTERY_SWITCH
176 if ((power_input_status() & POWER_INPUT_BATTERY
) == 0)
179 return battery_percent
;
182 /* Returns filtered battery voltage [millivolts] */
183 unsigned int battery_voltage(void)
185 return battery_millivolts
;
188 /* Tells if the battery level is safe for disk writes */
189 bool battery_level_safe(void)
191 #if defined(NO_LOW_BATTERY_SHUTDOWN)
193 #elif defined(HAVE_BATTERY_SWITCH)
194 /* Cannot rely upon the battery reading to be valid and the
195 * device could be powered externally. */
196 return input_millivolts() > battery_level_dangerous
[battery_type
];
198 return battery_millivolts
> battery_level_dangerous
[battery_type
];
202 void set_poweroff_timeout(int timeout
)
204 poweroff_timeout
= timeout
;
207 void set_sleep_timer(int seconds
)
210 sleeptimer_active
= true;
211 sleeptimer_endtick
= current_tick
+ seconds
* HZ
;
214 sleeptimer_active
= false;
215 sleeptimer_endtick
= 0;
219 int get_sleep_timer(void)
221 if (sleeptimer_active
)
222 return (sleeptimer_endtick
- current_tick
) / HZ
;
227 /* look into the percent_to_volt_* table and get a realistic battery level */
228 static int voltage_to_percent(int voltage
, const short* table
)
230 if (voltage
<= table
[0]) {
233 else if (voltage
>= table
[10]) {
237 /* search nearest value */
240 while (i
< 10 && table
[i
+1] < voltage
)
243 /* interpolate linear between the smaller and greater value */
244 /* Tens digit, 10% per entry, ones digit: interpolated */
245 return i
*10 + (voltage
- table
[i
])*10 / (table
[i
+1] - table
[i
]);
249 /* update battery level and estimated runtime, called once per minute or
250 * when battery capacity / type settings are changed */
251 static int voltage_to_battery_level(int battery_millivolts
)
255 #if CONFIG_CHARGING >= CHARGING_MONITOR
256 if (charging_state()) {
257 /* battery level is defined to be < 100% until charging is finished */
258 level
= voltage_to_percent(battery_millivolts
,
259 percent_to_volt_charge
);
264 #endif /* CONFIG_CHARGING >= CHARGING_MONITOR */
266 /* DISCHARGING or error state */
267 level
= voltage_to_percent(battery_millivolts
,
268 percent_to_volt_discharge
[battery_type
]);
274 static void battery_status_update(void)
276 int level
= voltage_to_battery_level(battery_millivolts
);
278 #ifdef CURRENT_NORMAL /*don't try to estimate run or charge
279 time without normal current defined*/
280 /* calculate estimated remaining running time */
281 #if CONFIG_CHARGING >= CHARGING_MONITOR
282 if (charging_state()) {
283 /* charging: remaining charging time */
284 powermgmt_est_runningtime_min
= (100 - level
)*battery_capacity
*60
285 / 100 / (CURRENT_MAX_CHG
- runcurrent());
290 /* discharging: remaining running time */
291 if (battery_millivolts
> percent_to_volt_discharge
[0][0]) {
292 /* linear extrapolation */
293 powermgmt_est_runningtime_min
= (level
+ battery_percent
)*60
294 * battery_capacity
/ 200 / runcurrent();
296 if (0 > powermgmt_est_runningtime_min
) {
297 powermgmt_est_runningtime_min
= 0;
300 powermgmt_est_runningtime_min
=-1;
303 battery_percent
= level
;
304 send_battery_level_event();
308 * We shut off in the following cases:
309 * 1) The unit is idle, not playing music
310 * 2) The unit is playing music, but is paused
311 * 3) The battery level has reached shutdown limit
313 * We do not shut off in the following cases:
314 * 1) The USB is connected
315 * 2) The charger is connected
316 * 3) We are recording, or recording with pause
317 * 4) The radio is playing
319 static void handle_auto_poweroff(void)
321 long timeout
= poweroff_timeout
*60*HZ
;
322 int audio_stat
= audio_status();
323 long tick
= current_tick
;
327 * Inhibit shutdown as long as the charger is plugged in. If it is
328 * unplugged, wait for a timeout period and then shut down.
330 if (charger_input_state
== CHARGER
|| audio_stat
== AUDIO_STATUS_PLAY
) {
331 last_event_tick
= current_tick
;
335 if (!shutdown_timeout
&& query_force_shutdown()) {
342 !(get_radio_status() & FMRADIO_PLAYING
) &&
346 (audio_stat
== (AUDIO_STATUS_PLAY
| AUDIO_STATUS_PAUSE
) &&
347 !sleeptimer_active
))) {
349 if (TIME_AFTER(tick
, last_event_tick
+ timeout
) &&
350 TIME_AFTER(tick
, storage_last_disk_activity() + timeout
)) {
354 else if (sleeptimer_active
) {
355 /* Handle sleeptimer */
356 if (TIME_AFTER(tick
, sleeptimer_endtick
)) {
360 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
361 || charger_input_state
!= NO_CHARGER
364 DEBUGF("Sleep timer timeout. Stopping...\n");
366 backlight_off(); /* Nighty, nighty... */
369 DEBUGF("Sleep timer timeout. Shutting off...\n");
376 #ifdef CURRENT_NORMAL /*check that we have a current defined in a config file*/
379 * Estimate how much current we are drawing just to run.
381 static int runcurrent(void)
383 int current
= CURRENT_NORMAL
;
387 #ifdef HAVE_USB_POWER
388 #if (CURRENT_USB < CURRENT_NORMAL)
395 current
= CURRENT_USB
;
398 #if defined(HAVE_BACKLIGHT)
399 if (backlight_get_current_timeout() == 0) /* LED always on */
400 current
+= CURRENT_BACKLIGHT
;
403 #if defined(HAVE_RECORDING) && defined(CURRENT_RECORD)
404 if (audio_status() & AUDIO_STATUS_RECORD
)
405 current
+= CURRENT_RECORD
;
408 #ifdef HAVE_SPDIF_POWER
410 current
+= CURRENT_SPDIF_OUT
;
413 #ifdef HAVE_REMOTE_LCD
415 current
+= CURRENT_REMOTE
;
417 #endif /* BOOTLOADER */
422 #endif /* CURRENT_NORMAL */
424 /* Check to see whether or not we've received an alarm in the last second */
425 #ifdef HAVE_RTC_ALARM
426 static void power_thread_rtc_process(void)
428 if (rtc_check_alarm_flag())
429 rtc_enable_alarm(false);
433 /* switch off unit if battery level is too low for reliable operation */
434 bool query_force_shutdown(void)
436 #if defined(NO_LOW_BATTERY_SHUTDOWN)
438 #elif defined(HAVE_BATTERY_SWITCH)
439 /* Cannot rely upon the battery reading to be valid and the
440 * device could be powered externally. */
441 return input_millivolts() < battery_level_shutoff
[battery_type
];
443 return battery_millivolts
< battery_level_shutoff
[battery_type
];
447 #if defined(HAVE_BATTERY_SWITCH) || defined(HAVE_RESET_BATTERY_FILTER)
449 * Reset the battery voltage filter to a new value and update the
452 void reset_battery_filter(int millivolts
)
454 avgbat
= millivolts
* BATT_AVE_SAMPLES
;
455 battery_millivolts
= millivolts
;
456 battery_status_update();
458 #endif /* HAVE_BATTERY_SWITCH */
460 /** Generic charging algorithms for common charging types **/
461 #if CONFIG_CHARGING == 0 || CONFIG_CHARGING == CHARGING_SIMPLE
462 static inline void powermgmt_init_target(void)
467 static inline void charging_algorithm_step(void)
472 static inline void charging_algorithm_close(void)
476 #elif CONFIG_CHARGING == CHARGING_MONITOR
478 * Monitor CHARGING/DISCHARGING state.
480 static inline void powermgmt_init_target(void)
485 static inline void charging_algorithm_step(void)
487 switch (charger_input_state
)
489 case CHARGER_PLUGGED
:
491 if (charging_state()) {
492 charge_state
= CHARGING
;
496 case CHARGER_UNPLUGGED
:
498 charge_state
= DISCHARGING
;
503 static inline void charging_algorithm_close(void)
507 #endif /* CONFIG_CHARGING == * */
510 /* Shortcut function calls - compatibility, simplicity. */
512 /* Returns true if any power input is capable of charging. */
513 bool charger_inserted(void)
515 return power_thread_inputs
& POWER_INPUT_CHARGER
;
518 /* Returns true if any power input is connected - charging-capable
520 bool power_input_present(void)
522 return power_thread_inputs
& POWER_INPUT
;
526 * Detect charger inserted. Return true if the state is transistional.
528 static inline bool detect_charger(unsigned int pwr
)
531 * Detect charger plugged/unplugged transitions. On a plugged or
532 * unplugged event, we return immediately, run once through the main
533 * loop (including the subroutines), and end up back here where we
534 * transition to the appropriate steady state charger on/off state.
536 if (pwr
& POWER_INPUT_CHARGER
) {
537 switch (charger_input_state
)
540 case CHARGER_UNPLUGGED
:
541 charger_input_state
= CHARGER_PLUGGED
;
544 case CHARGER_PLUGGED
:
545 queue_broadcast(SYS_CHARGER_CONNECTED
, 0);
546 last_sent_battery_level
= 0;
547 charger_input_state
= CHARGER
;
555 else { /* charger not inserted */
556 switch (charger_input_state
)
562 case CHARGER_UNPLUGGED
:
563 queue_broadcast(SYS_CHARGER_DISCONNECTED
, 0);
564 last_sent_battery_level
= 100;
565 charger_input_state
= NO_CHARGER
;
568 case CHARGER_PLUGGED
:
570 charger_input_state
= CHARGER_UNPLUGGED
;
575 /* Transitional state */
578 #endif /* CONFIG_CHARGING */
581 * Monitor the presence of a charger and perform critical frequent steps
582 * such as running the battery voltage filter.
584 static inline void power_thread_step(void)
586 /* If the power off timeout expires, the main thread has failed
587 to shut down the system, and we need to force a power off */
588 if (shutdown_timeout
) {
589 shutdown_timeout
-= POWER_THREAD_STEP_TICKS
;
591 if (shutdown_timeout
<= 0)
595 #ifdef HAVE_RTC_ALARM
596 power_thread_rtc_process();
600 * Do a digital exponential filter. We don't sample the battery if
601 * the disk is spinning unless we are in USB mode (the disk will most
602 * likely always be spinning in USB mode) or charging.
604 if (!storage_disk_is_active() || usb_inserted()
605 #if CONFIG_CHARGING >= CHARGING_MONITOR
606 || charger_input_state
== CHARGER
609 avgbat
+= battery_adc_voltage() - avgbat
/ BATT_AVE_SAMPLES
;
611 * battery_millivolts is the millivolt-scaled filtered battery value.
613 battery_millivolts
= avgbat
/ BATT_AVE_SAMPLES
;
615 /* update battery status every time an update is available */
616 battery_status_update();
618 else if (battery_percent
< 8) {
620 * If battery is low, observe voltage during disk activity.
621 * Shut down if voltage drops below shutoff level and we are not
622 * using NiMH or Alkaline batteries.
624 battery_millivolts
= (battery_adc_voltage() +
625 battery_millivolts
+ 1) / 2;
627 /* update battery status every time an update is available */
628 battery_status_update();
630 if (!shutdown_timeout
&& query_force_shutdown()) {
634 avgbat
+= battery_millivolts
- avgbat
/ BATT_AVE_SAMPLES
;
637 } /* power_thread_step */
639 static void power_thread(void)
641 long next_power_hist
;
643 /* Delay reading the first battery level */
645 while (battery_adc_voltage() > 4200) /* gives false readings initially */
652 /* Initialize power input status before calling other routines. */
653 power_thread_inputs
= power_input_status();
656 /* initialize the voltages for the exponential filter */
657 avgbat
= battery_adc_voltage() + 15;
659 #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */
660 /* The battery voltage is usually a little lower directly after
661 turning on, because the disk was used heavily. Raise it by 5% */
663 if (!charger_inserted()) /* only if charger not connected */
666 avgbat
+= (percent_to_volt_discharge
[battery_type
][6] -
667 percent_to_volt_discharge
[battery_type
][5]) / 2;
669 #endif /* HAVE_DISK_STORAGE */
671 avgbat
= avgbat
* BATT_AVE_SAMPLES
;
672 battery_millivolts
= avgbat
/ BATT_AVE_SAMPLES
;
673 power_history
[0] = battery_millivolts
;
676 if (charger_inserted()) {
677 battery_percent
= voltage_to_percent(battery_millivolts
,
678 percent_to_volt_charge
);
683 battery_percent
= voltage_to_percent(battery_millivolts
,
684 percent_to_volt_discharge
[battery_type
]);
685 battery_percent
+= battery_percent
< 100;
688 powermgmt_init_target();
690 next_power_hist
= current_tick
+ HZ
*60;
695 unsigned int pwr
= power_input_status();
696 #ifdef HAVE_BATTERY_SWITCH
697 if ((pwr
^ power_thread_inputs
) & POWER_INPUT_BATTERY
) {
699 reset_battery_filter(battery_adc_voltage());
702 power_thread_inputs
= pwr
;
704 if (!detect_charger(pwr
))
705 #endif /* CONFIG_CHARGING */
708 sleep(POWER_THREAD_STEP_TICKS
);
710 /* Do common power tasks */
714 /* Perform target tasks */
715 charging_algorithm_step();
717 if (TIME_BEFORE(current_tick
, next_power_hist
))
720 /* increment to ensure there is a record for every minute
721 * rather than go forward from the current tick */
722 next_power_hist
+= HZ
*60;
724 /* rotate the power history */
725 memmove(&power_history
[1], &power_history
[0],
726 sizeof(power_history
) - sizeof(power_history
[0]));
728 /* insert new value at the start, in millivolts 8-) */
729 power_history
[0] = battery_millivolts
;
731 handle_auto_poweroff();
735 void powermgmt_init(void)
737 create_thread(power_thread
, power_stack
, sizeof(power_stack
), 0,
738 power_thread_name
IF_PRIO(, PRIORITY_SYSTEM
)
742 /* Various hardware housekeeping tasks relating to shutting down the player */
743 void shutdown_hw(void)
745 charging_algorithm_close();
748 if (battery_level_safe()) { /* do not save on critical battery */
749 #ifdef HAVE_LCD_BITMAP
750 glyph_cache_save(NULL
);
753 /* Commit pending writes if needed. Even though we don't do write caching,
754 things like flash translation layers may need this to commit scattered
755 pages to there final locations. So far only used for iPod Nano 2G. */
756 #ifdef HAVE_STORAGE_FLUSH
760 if (storage_disk_is_active())
764 while (storage_disk_is_active())
767 #if CONFIG_CODEC == SWCODEC
773 /* If HD is still active we try to wait for spindown, otherwise the
774 shutdown_timeout in power_thread_step will force a power off */
775 while (storage_disk_is_active())
778 #ifndef HAVE_LCD_COLOR
781 #ifdef HAVE_REMOTE_LCD
782 lcd_remote_set_contrast(0);
784 #ifdef HAVE_LCD_SHUTDOWN
788 /* Small delay to make sure all HW gets time to flush. Especially
789 eeprom chips are quite slow and might be still writing the last
795 void sys_poweroff(void)
798 logf("sys_poweroff()");
799 /* If the main thread fails to shut down the system, we will force a
800 power off after an 20 second timeout - 28 seconds if recording */
801 if (shutdown_timeout
== 0) {
802 #if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)
803 pcf50606_reset_timeout(); /* Reset timer on first attempt only */
805 #ifdef HAVE_RECORDING
806 if (audio_status() & AUDIO_STATUS_RECORD
)
807 shutdown_timeout
+= HZ
*8;
810 /* The FTL alone may take half a minute to shut down cleanly. */
811 shutdown_timeout
+= HZ
*60;
813 shutdown_timeout
+= HZ
*20;
817 queue_broadcast(SYS_POWEROFF
, 0);
818 #endif /* BOOTLOADER */
821 void cancel_shutdown(void)
823 logf("cancel_shutdown()");
825 #if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)
826 /* TODO: Move some things to target/ tree */
827 if (shutdown_timeout
)
828 pcf50606_reset_timeout();
831 shutdown_timeout
= 0;
833 #endif /* PLATFORM_NATIVE */
835 /* Send system battery level update events on reaching certain significant
836 levels. This must be called after battery_percent has been updated. */
837 void send_battery_level_event(void)
839 static const int levels
[] = { 5, 15, 30, 50, 0 };
840 const int *level
= levels
;
844 if (battery_percent
<= *level
&& last_sent_battery_level
> *level
) {
845 last_sent_battery_level
= *level
;
846 queue_broadcast(SYS_BATTERY_UPDATE
, last_sent_battery_level
);