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 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
35 #include "mp3_playback.h"
37 #include "powermgmt.h"
38 #include "backlight.h"
46 #elif defined(HAVE_TLV320)
48 #elif defined(HAVE_WM8758)
50 #elif defined(HAVE_WM8975)
53 #ifdef HAVE_LCD_BITMAP
57 #include "lcd-remote.h"
62 #if defined(IAUDIO_X5) && !defined (SIMULATOR)
67 * Define DEBUG_FILE to create a csv (spreadsheet) with battery information
68 * in it (one sample per minute). This is only for very low level debug.
71 #if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL)
73 #define DEBUG_FILE_NAME "/powermgmt.csv"
74 #define DEBUG_MESSAGE_LEN 133
75 static char debug_message
[DEBUG_MESSAGE_LEN
];
76 #define DEBUG_STACK ((0x1000)/sizeof(long))
77 static int fd
; /* write debug information to this file */
83 static int shutdown_timeout
= 0;
85 #ifdef SIMULATOR /***********************************************************/
87 #define TIME2CHANGE 10 /* change levels every 10 seconds */
88 #define BATT_MINCVOLT 250 /* minimum centivolts of battery */
89 #define BATT_MAXCVOLT 450 /* maximum centivolts of battery */
90 #define BATT_MAXRUNTIME (10 * 60) /* maximum runtime with full battery in minutes */
92 static unsigned int batt_centivolts
= (unsigned int)BATT_MAXCVOLT
;
93 static int batt_level
= 100; /* battery capacity level in percent */
94 static int batt_time
= BATT_MAXRUNTIME
; /* estimated remaining time in minutes */
95 static time_t last_change
= 0;
97 static void battery_status_update(void)
102 if (last_change
< (now
- TIME2CHANGE
)) {
105 /* change the values: */
106 batt_centivolts
-= (unsigned int)(BATT_MAXCVOLT
- BATT_MINCVOLT
) / 11;
107 if (batt_centivolts
< (unsigned int)BATT_MINCVOLT
)
108 batt_centivolts
= (unsigned int)BATT_MAXCVOLT
;
110 batt_level
= 100 * (batt_centivolts
- BATT_MINCVOLT
) / (BATT_MAXCVOLT
- BATT_MINCVOLT
);
111 batt_time
= batt_level
* BATT_MAXRUNTIME
/ 100;
115 void battery_read_info(int *adc
, int *voltage
, int *level
)
117 battery_status_update();
120 *adc
= batt_centivolts
; /* just return something */
123 *voltage
= batt_centivolts
;
129 unsigned int battery_voltage(void)
131 battery_status_update();
132 return batt_centivolts
;
135 int battery_level(void)
137 battery_status_update();
141 int battery_time(void)
143 battery_status_update();
147 bool battery_level_safe(void)
149 return battery_level() >= 10;
152 void set_poweroff_timeout(int timeout
)
157 void set_battery_capacity(int capacity
)
162 void reset_poweroff_timer(void)
167 #else /* not SIMULATOR ******************************************************/
169 static const int poweroff_idle_timeout_value
[15] =
171 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 30, 45, 60
174 static const unsigned int battery_level_dangerous
[BATTERY_TYPES_COUNT
] =
176 #if CONFIG_BATTERY == BATT_LIION2200 /* FM Recorder, LiIon */
178 #elif CONFIG_BATTERY == BATT_3AAA /* Ondio */
179 310, 345 /* alkaline, NiHM */
180 #elif CONFIG_BATTERY == BATT_1AA /* iRiver iFP */
181 105, 115 /* alkaline, NiHM */
182 #elif CONFIG_BATTERY == BATT_LIPOL1300 /* iRiver H1x0 */
184 #elif CONFIG_BATTERY == BATT_IAUDIO_X5
186 #elif CONFIG_BATTERY == BATT_LPCS355385 /* iriver H10 20GB */
188 #elif CONFIG_BATTERY == BATT_BP009 /* iriver H10 5/6GB */
190 #else /* Player/recorder, NiMH */
195 static const short percent_to_volt_discharge
[BATTERY_TYPES_COUNT
][11] =
196 /* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */
198 #if CONFIG_BATTERY == BATT_LIION2200
199 /* measured values */
200 { 260, 285, 295, 303, 311, 320, 330, 345, 360, 380, 400 }
201 #elif CONFIG_BATTERY == BATT_3AAA
202 /* measured values */
203 { 280, 325, 341, 353, 364, 374, 385, 395, 409, 427, 475 }, /* alkaline */
204 { 310, 355, 363, 369, 372, 374, 376, 378, 380, 386, 405 } /* NiMH */
205 #elif CONFIG_BATTERY == BATT_LIPOL1300
206 /* Below 337 the backlight starts flickering during HD access */
207 /* Calibrated for Ionity 1900 mAh battery. If necessary, re-calibrate
208 * for the 1300 mAh stock battery. */
209 // { 337, 358, 365, 369, 372, 377, 383, 389, 397, 406, 413 }
210 { 337, 366, 372, 374, 378, 381, 385, 392, 399, 408, 417 }
211 #elif CONFIG_BATTERY == BATT_IAUDIO_X5
212 /* iAudio x5 series - still experimenting with best curve */
213 // Lithium ion discharge curve
214 { 355, 356, 357, 359, 362, 365, 369, 374, 380, 387, 395 }
216 // { 355, 360, 364, 369, 373, 378, 382, 387, 391, 390, 400 }
217 // { 355, 359, 363, 367, 371, 375, 379, 383, 387, 391, 395 }
218 #elif CONFIG_BATTERY == BATT_LPCS355385
219 /* iriver H10 20GB */
220 { 376, 380, 385, 387, 390, 395, 402, 407, 411, 418, 424 }
221 #elif CONFIG_BATTERY == BATT_BP009
222 /* iriver H10 5/6GB */
223 { 372, 374, 380, 382, 384, 388, 394, 402, 406, 415, 424 }
224 #elif CONFIG_BATTERY == BATT_1AA
225 /* These values are the same as for 3AAA divided by 3. */
226 /* May need recalibration. */
227 { 93, 108, 114, 118, 121, 125, 128, 132, 136, 142, 158 }, /* alkaline */
228 { 103, 118, 121, 123, 124, 125, 126, 127, 128, 129, 135 } /* NiMH */
230 /* original values were taken directly after charging, but it should show
231 100% after turning off the device for some hours, too */
232 { 450, 481, 491, 497, 503, 507, 512, 514, 517, 525, 540 }
233 /* orig. values: ...,528,560 */
237 #ifdef CONFIG_CHARGING
238 charger_input_state_type charger_input_state IDATA_ATTR
;
240 /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */
241 static const short percent_to_volt_charge
[11] =
243 #if CONFIG_BATTERY == BATT_LIPOL1300
244 /* Calibrated for 1900 mAh Ionity battery (estimated 90% charge when
245 entering in trickle-charging). We will never reach 100%. */
246 340, 390, 394, 399, 400, 404, 407, 413, 417, 422, 426
247 #elif CONFIG_BATTERY == BATT_LPCS355385
248 /* iriver H10 20GB */
249 399, 403, 406, 408, 410, 412, 415, 418, 422, 426, 431
250 #elif CONFIG_BATTERY == BATT_BP009
251 /* iriver H10 5/6GB: Not yet calibrated */
252 388, 392, 396, 400, 406, 410, 415, 419, 424, 428, 433
254 /* values guessed, see
255 http://www.seattlerobotics.org/encoder/200210/LiIon2.pdf until someone
256 measures voltages over a charging cycle */
257 476, 544, 551, 556, 561, 564, 566, 576, 582, 584, 585 /* NiMH */
260 #endif /* CONFIG_CHARGING */
262 #if CONFIG_CHARGING >= CHARGING_MONITOR
263 charge_state_type charge_state
; /* charging mode */
266 #if CONFIG_CHARGING == CHARGING_CONTROL
267 int long_delta
; /* long term delta battery voltage */
268 int short_delta
; /* short term delta battery voltage */
269 bool disk_activity_last_cycle
= false; /* flag set to aid charger time
271 char power_message
[POWER_MESSAGE_LEN
] = ""; /* message that's shown in
273 /* percentage at which charging
275 int powermgmt_last_cycle_startstop_min
= 0; /* how many minutes ago was the
278 int powermgmt_last_cycle_level
= 0; /* which level had the
279 batteries at this time? */
280 int trickle_sec
= 0; /* how many seconds should the
281 charger be enabled per
284 int pid_p
= 0; /* PID proportional term */
285 int pid_i
= 0; /* PID integral term */
286 #endif /* CONFIG_CHARGING == CHARGING_CONTROL */
289 * Average battery voltage and charger voltage, filtered via a digital
290 * exponential filter.
292 static unsigned int battery_centivolts
;/* filtered battery voltage, centvolts */
293 static unsigned int avgbat
; /* average battery voltage (filtering) */
294 #define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */
296 /* battery level (0-100%) of this minute, updated once per minute */
297 static int battery_percent
= -1;
298 static int battery_capacity
= BATTERY_CAPACITY_DEFAULT
; /* default value, mAh */
299 static int battery_type
= 0;
301 /* Power history: power_history[0] is the newest sample */
302 unsigned short power_history
[POWER_HISTORY_LEN
];
304 static char power_stack
[DEFAULT_STACK_SIZE
+ DEBUG_STACK
];
305 static const char power_thread_name
[] = "power";
307 static int poweroff_timeout
= 0;
308 static int powermgmt_est_runningtime_min
= -1;
310 static bool sleeptimer_active
= false;
311 static long sleeptimer_endtick
;
313 static long last_event_tick
;
315 static int voltage_to_battery_level(int battery_centivolts
);
316 static void battery_status_update(void);
317 static int runcurrent(void);
319 void battery_read_info(int *adc
, int *voltage
, int *level
)
321 int adc_battery
= adc_read(ADC_UNREG_POWER
);
322 int centivolts
= adc_battery
*BATTERY_SCALE_FACTOR
/ 10000;
328 *voltage
= centivolts
;
331 *level
= voltage_to_battery_level(centivolts
);
334 unsigned int battery_voltage(void)
336 return battery_centivolts
;
339 void reset_poweroff_timer(void)
341 last_event_tick
= current_tick
;
344 #if BATTERY_TYPES_COUNT > 1
345 void set_battery_type(int type
)
347 if (type
!= battery_type
) {
349 battery_status_update(); /* recalculate the battery status */
354 void set_battery_capacity(int capacity
)
356 battery_capacity
= capacity
;
357 if (battery_capacity
> BATTERY_CAPACITY_MAX
)
358 battery_capacity
= BATTERY_CAPACITY_MAX
;
359 if (battery_capacity
< BATTERY_CAPACITY_MIN
)
360 battery_capacity
= BATTERY_CAPACITY_MIN
;
361 battery_status_update(); /* recalculate the battery status */
364 int battery_time(void)
366 return powermgmt_est_runningtime_min
;
369 /* Returns battery level in percent */
370 int battery_level(void)
372 return battery_percent
;
375 /* Tells if the battery level is safe for disk writes */
376 bool battery_level_safe(void)
378 return battery_centivolts
> battery_level_dangerous
[battery_type
];
381 void set_poweroff_timeout(int timeout
)
383 poweroff_timeout
= timeout
;
386 void set_sleep_timer(int seconds
)
389 sleeptimer_active
= true;
390 sleeptimer_endtick
= current_tick
+ seconds
* HZ
;
393 sleeptimer_active
= false;
394 sleeptimer_endtick
= 0;
398 int get_sleep_timer(void)
400 if(sleeptimer_active
)
401 return (sleeptimer_endtick
- current_tick
) / HZ
;
406 /* look into the percent_to_volt_* table and get a realistic battery level
408 static int voltage_to_percent(int voltage
, const short* table
)
410 if (voltage
<= table
[0])
413 if (voltage
>= table
[10])
416 /* search nearest value */
418 while ((i
< 10) && (table
[i
+1] < voltage
))
420 /* interpolate linear between the smaller and greater value */
421 return (i
* 10) /* Tens digit, 10% per entry */
422 + (((voltage
- table
[i
]) * 10)
423 / (table
[i
+1] - table
[i
])); /* Ones digit: interpolated */
427 /* update battery level and estimated runtime, called once per minute or
428 * when battery capacity / type settings are changed */
429 static int voltage_to_battery_level(int battery_centivolts
)
433 #if CONFIG_CHARGING >= CHARGING_MONITOR
434 if (charge_state
== DISCHARGING
) {
435 level
= voltage_to_percent(battery_centivolts
,
436 percent_to_volt_discharge
[battery_type
]);
438 else if (charge_state
== CHARGING
) {
439 /* battery level is defined to be < 100% until charging is finished */
440 level
= MIN(voltage_to_percent(battery_centivolts
,
441 percent_to_volt_charge
), 99);
443 else { /* in topoff/trickle charge, the battery is by definition 100% full */
447 /* always use the discharge table */
448 level
= voltage_to_percent(battery_centivolts
,
449 percent_to_volt_discharge
[battery_type
]);
455 static void battery_status_update(void)
457 int level
= voltage_to_battery_level(battery_centivolts
);
459 #ifndef HAVE_MMC /* this adjustment is only needed for HD based */
460 if (battery_percent
== -1) { /* first run of this procedure */
461 /* The battery voltage is usually a little lower directly after
462 turning on, because the disk was used heavily. Raise it by 5. % */
463 level
= (level
> 95) ? 100 : level
+ 5;
466 battery_percent
= level
;
468 /* calculate estimated remaining running time */
469 /* discharging: remaining running time */
470 /* charging: remaining charging time */
471 #if CONFIG_CHARGING >= CHARGING_MONITOR
472 if (charge_state
== CHARGING
) {
473 powermgmt_est_runningtime_min
= (100 - level
) * battery_capacity
/ 100
474 * 60 / (CURRENT_MAX_CHG
- runcurrent());
479 powermgmt_est_runningtime_min
= level
* battery_capacity
/ 100
485 * We shut off in the following cases:
486 * 1) The unit is idle, not playing music
487 * 2) The unit is playing music, but is paused
489 * We do not shut off in the following cases:
490 * 1) The USB is connected
491 * 2) The charger is connected
492 * 3) We are recording, or recording with pause
493 * 4) The radio is playing
495 static void handle_auto_poweroff(void)
497 long timeout
= poweroff_idle_timeout_value
[poweroff_timeout
]*60*HZ
;
498 int audio_stat
= audio_status();
500 #ifdef CONFIG_CHARGING
502 * Inhibit shutdown as long as the charger is plugged in. If it is
503 * unplugged, wait for a timeout period and then shut down.
505 if(charger_input_state
== CHARGER
|| audio_stat
== AUDIO_STATUS_PLAY
) {
506 last_event_tick
= current_tick
;
511 #if defined(CONFIG_TUNER) && !defined(BOOTLOADER)
512 (!(get_radio_status() & FMRADIO_PLAYING
)) &&
515 ((audio_stat
== 0) ||
516 ((audio_stat
== (AUDIO_STATUS_PLAY
| AUDIO_STATUS_PAUSE
)) &&
517 !sleeptimer_active
)))
519 if(TIME_AFTER(current_tick
, last_event_tick
+ timeout
) &&
520 TIME_AFTER(current_tick
, last_disk_activity
+ timeout
))
527 /* Handle sleeptimer */
528 if(sleeptimer_active
&& !usb_inserted())
530 if(TIME_AFTER(current_tick
, sleeptimer_endtick
))
533 #if defined(CONFIG_CHARGING) && !defined(HAVE_POWEROFF_WHILE_CHARGING)
534 if((charger_input_state
== CHARGER
) ||
535 (charger_input_state
== CHARGER_PLUGGED
))
537 DEBUGF("Sleep timer timeout. Stopping...\n");
539 backlight_off(); /* Nighty, nighty... */
544 DEBUGF("Sleep timer timeout. Shutting off...\n");
553 * Estimate how much current we are drawing just to run.
555 static int runcurrent(void)
559 #if MEM == 8 && !defined(HAVE_MMC)
560 /* assuming 192 kbps, the running time is 22% longer with 8MB */
561 current
= (CURRENT_NORMAL
*100/122);
563 current
= CURRENT_NORMAL
;
564 #endif /* MEM == 8 */
567 #if defined(HAVE_USB_POWER)
568 #if (CURRENT_USB < CURRENT_NORMAL)
576 current
= CURRENT_USB
;
579 #if defined(CONFIG_BACKLIGHT) && !defined(BOOTLOADER)
580 if (backlight_get_current_timeout() == 0) /* LED always on */
581 current
+= CURRENT_BACKLIGHT
;
588 /* Check to see whether or not we've received an alarm in the last second */
589 #ifdef HAVE_ALARM_MOD
590 static void power_thread_rtc_process(void)
592 if (rtc_check_alarm_flag()) {
593 rtc_enable_alarm(false);
599 * This function is called to do the relativly long sleep waits from within the
600 * main power_thread loop while at the same time servicing any other periodic
601 * functions in the power thread which need to be called at a faster periodic
602 * rate than the slow periodic rate of the main power_thread loop.
604 * While we are waiting for the time to expire, we average the battery
607 static void power_thread_sleep(int ticks
)
613 #ifdef CONFIG_CHARGING
615 * Detect charger plugged/unplugged transitions. On a plugged or
616 * unplugged event, we return immediately, run once through the main
617 * loop (including the subroutines), and end up back here where we
618 * transition to the appropriate steady state charger on/off state.
620 if(charger_inserted()
621 #ifdef HAVE_USB_POWER
625 switch(charger_input_state
) {
627 case CHARGER_UNPLUGGED
:
628 charger_input_state
= CHARGER_PLUGGED
;
630 case CHARGER_PLUGGED
:
631 queue_broadcast(SYS_CHARGER_CONNECTED
, NULL
);
632 charger_input_state
= CHARGER
;
637 } else { /* charger not inserted */
638 switch(charger_input_state
) {
641 case CHARGER_UNPLUGGED
:
642 queue_broadcast(SYS_CHARGER_DISCONNECTED
, NULL
);
643 charger_input_state
= NO_CHARGER
;
645 case CHARGER_PLUGGED
:
647 charger_input_state
= CHARGER_UNPLUGGED
;
652 #if CONFIG_CHARGING == CHARGING_MONITOR
653 switch (charger_input_state
) {
654 case CHARGER_UNPLUGGED
:
656 charge_state
= DISCHARGING
;
658 case CHARGER_PLUGGED
:
660 if (charging_state()) {
661 charge_state
= CHARGING
;
663 charge_state
= DISCHARGING
;
668 #endif /* CONFIG_CHARGING == CHARGING_MONITOR */
670 small_ticks
= MIN(HZ
/2, ticks
);
672 ticks
-= small_ticks
;
674 /* If the power off timeout expires, the main thread has failed
675 to shut down the system, and we need to force a power off */
676 if(shutdown_timeout
) {
677 shutdown_timeout
-= small_ticks
;
678 if(shutdown_timeout
<= 0)
682 #ifdef HAVE_ALARM_MOD
683 power_thread_rtc_process();
687 * Do a digital exponential filter. We don't sample the battery if
688 * the disk is spinning unless we are in USB mode (the disk will most
689 * likely always be spinning in USB mode).
691 if (!ata_disk_is_active() || usb_inserted()) {
692 avgbat
= avgbat
- (avgbat
/ BATT_AVE_SAMPLES
) +
693 adc_read(ADC_UNREG_POWER
) * BATTERY_SCALE_FACTOR
;
695 * battery_centivolts is the centivolt-scaled filtered battery value.
697 battery_centivolts
= avgbat
/ BATT_AVE_SAMPLES
/ 10000;
699 /* update battery status every time an update is available */
700 battery_status_update();
703 #if CONFIG_CHARGING == CHARGING_CONTROL
704 if (ata_disk_is_active()) {
705 /* flag hdd use for charging calculation */
706 disk_activity_last_cycle
= true;
709 #if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL)
711 * If we have a lot of pending writes or if the disk is spining,
712 * fsync the debug log file.
715 ((wrcount
> 0) && ata_disk_is_active())) {
725 * This power thread maintains a history of battery voltage
726 * and implements a charging algorithm.
727 * For a complete description of the charging algorithm read
728 * docs/CHARGING_ALGORITHM.
731 static void power_thread(void)
734 short *phps
, *phpd
; /* power history rotation pointers */
735 #if CONFIG_CHARGING == CHARGING_CONTROL
736 unsigned int target_voltage
= TRICKLE_VOLTAGE
; /* desired topoff/trickle
738 int charge_max_time_idle
= 0; /* max. charging duration, calculated at
739 * beginning of charging */
740 int charge_max_time_now
= 0; /* max. charging duration including
742 int minutes_disk_activity
= 0; /* count minutes of hdd use during
744 int last_disk_activity
= CHARGE_END_LONGD
+ 1; /* last hdd use x mins ago */
747 /* initialize the voltages for the exponential filter */
748 avgbat
= adc_read(ADC_UNREG_POWER
) * BATTERY_SCALE_FACTOR
*
750 battery_centivolts
= avgbat
/ BATT_AVE_SAMPLES
/ 10000;
752 #if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL)
759 /* rotate the power history */
760 phpd
= &power_history
[POWER_HISTORY_LEN
- 1];
762 for (i
= 0; i
< POWER_HISTORY_LEN
-1; i
++)
765 /* insert new value at the start, in centivolts 8-) */
766 power_history
[0] = battery_centivolts
;
768 #if CONFIG_CHARGING == CHARGING_CONTROL
769 if (charger_input_state
== CHARGER_PLUGGED
) {
772 snprintf(power_message
, POWER_MESSAGE_LEN
, "Charger plugged in");
774 * The charger was just plugged in. If the battery level is
775 * nearly charged, just trickle. If the battery is low, start
776 * a full charge cycle. If the battery level is in between,
777 * top-off and then trickle.
779 if(battery_percent
> START_TOPOFF_CHG
) {
780 powermgmt_last_cycle_level
= battery_percent
;
781 powermgmt_last_cycle_startstop_min
= 0;
782 if(battery_percent
>= START_TRICKLE_CHG
) {
783 charge_state
= TRICKLE
;
784 target_voltage
= TRICKLE_VOLTAGE
;
786 charge_state
= TOPOFF
;
787 target_voltage
= TOPOFF_VOLTAGE
;
791 * Start the charger full strength
793 i
= CHARGE_MAX_TIME_1500
* battery_capacity
/ 1500;
794 charge_max_time_idle
=
795 i
* (100 + 35 - battery_percent
) / 100;
796 if (charge_max_time_idle
> i
) {
797 charge_max_time_idle
= i
;
799 charge_max_time_now
= charge_max_time_idle
;
801 snprintf(power_message
, POWER_MESSAGE_LEN
,
802 "ChgAt %d%% max %dm", battery_level(),
803 charge_max_time_now
);
805 /* enable the charger after the max time calc is done,
806 because battery_level depends on if the charger is
808 DEBUGF("power: charger inserted and battery"
809 " not full, charging\n");
810 powermgmt_last_cycle_level
= battery_percent
;
811 powermgmt_last_cycle_startstop_min
= 0;
813 long_delta
= short_delta
= 999999;
814 charge_state
= CHARGING
;
817 if (charge_state
== CHARGING
) {
818 /* alter charge time max length with extra disk use */
819 if (disk_activity_last_cycle
) {
820 minutes_disk_activity
++;
821 charge_max_time_now
= charge_max_time_idle
+
822 (minutes_disk_activity
* 2 / 5);
823 disk_activity_last_cycle
= false;
824 last_disk_activity
= 0;
826 last_disk_activity
++;
829 * Check the delta voltage over the last X minutes so we can do
830 * our end-of-charge logic based on the battery level change.
831 *(no longer use minimum time as logic for charge end has 50
832 * minutes minimum charge built in)
834 if (powermgmt_last_cycle_startstop_min
> CHARGE_END_SHORTD
) {
835 short_delta
= power_history
[0] -
836 power_history
[CHARGE_END_SHORTD
- 1];
839 if (powermgmt_last_cycle_startstop_min
> CHARGE_END_LONGD
) {
841 * Scan the history: the points where measurement is taken need to
842 * be fairly static. (check prior to short delta 'area')
843 * (also only check first and last 10 cycles - delta in middle OK)
845 long_delta
= power_history
[0] -
846 power_history
[CHARGE_END_LONGD
- 1];
848 for(i
= CHARGE_END_SHORTD
; i
< CHARGE_END_SHORTD
+ 10; i
++) {
849 if(((power_history
[i
] - power_history
[i
+1]) > 5) ||
850 ((power_history
[i
] - power_history
[i
+1]) < -5)) {
855 for(i
= CHARGE_END_LONGD
- 11; i
< CHARGE_END_LONGD
- 1 ; i
++) {
856 if(((power_history
[i
] - power_history
[i
+1]) > 5) ||
857 ((power_history
[i
] - power_history
[i
+1]) < -5)) {
864 snprintf(power_message
, POWER_MESSAGE_LEN
,
865 "Chg %dm, max %dm", powermgmt_last_cycle_startstop_min
,
866 charge_max_time_now
);
868 * End of charge criteria (any qualify):
869 * 1) Charged a long time
870 * 2) DeltaV went negative for a short time ( & long delta static)
871 * 3) DeltaV was negative over a longer period (no disk use only)
872 * Note: short_delta and long_delta are centivolts
874 if ((powermgmt_last_cycle_startstop_min
>= charge_max_time_now
) ||
875 (short_delta
<= -5 && long_delta
< 5 ) || (long_delta
< -2 &&
876 last_disk_activity
> CHARGE_END_LONGD
)) {
877 if (powermgmt_last_cycle_startstop_min
> charge_max_time_now
) {
878 DEBUGF("power: powermgmt_last_cycle_startstop_min > charge_max_time_now, "
881 *have charged too long and deltaV detection did not
884 snprintf(power_message
, POWER_MESSAGE_LEN
,
885 "Chg tmout %d min", charge_max_time_now
);
887 * Switch to trickle charging. We skip the top-off
888 * since we've effectively done the top-off operation
889 * already since we charged for the maximum full
892 powermgmt_last_cycle_level
= battery_percent
;
893 powermgmt_last_cycle_startstop_min
= 0;
894 charge_state
= TRICKLE
;
897 * set trickle charge target to a relative voltage instead
898 * of an arbitrary value - the fully charged voltage may
899 * vary according to ambient temp, battery condition etc
900 * trickle target is -0.15v from full voltage acheived
901 * topup target is -0.05v from full voltage
903 target_voltage
= power_history
[0] - 15;
906 if(short_delta
<= -5) {
907 DEBUGF("power: short-term negative"
908 " delta, enough!\n");
909 snprintf(power_message
, POWER_MESSAGE_LEN
,
910 "end negd %d %dmin", short_delta
,
911 powermgmt_last_cycle_startstop_min
);
912 target_voltage
= power_history
[CHARGE_END_SHORTD
- 1]
915 DEBUGF("power: long-term small "
916 "positive delta, enough!\n");
917 snprintf(power_message
, POWER_MESSAGE_LEN
,
918 "end lowd %d %dmin", long_delta
,
919 powermgmt_last_cycle_startstop_min
);
920 target_voltage
= power_history
[CHARGE_END_LONGD
- 1]
924 * Switch to top-off charging.
926 powermgmt_last_cycle_level
= battery_percent
;
927 powermgmt_last_cycle_startstop_min
= 0;
928 charge_state
= TOPOFF
;
932 else if (charge_state
!= DISCHARGING
) /* top off or trickle */
935 *Time to switch from topoff to trickle?
937 if ((charge_state
== TOPOFF
) &&
938 (powermgmt_last_cycle_startstop_min
> TOPOFF_MAX_TIME
))
940 powermgmt_last_cycle_level
= battery_percent
;
941 powermgmt_last_cycle_startstop_min
= 0;
942 charge_state
= TRICKLE
;
943 target_voltage
= target_voltage
- 10;
946 * Adjust trickle charge time (proportional and integral terms).
947 * Note: I considered setting the level higher if the USB is
948 * plugged in, but it doesn't appear to be necessary and will
949 * generate more heat [gvb].
952 pid_p
= target_voltage
- battery_centivolts
;
953 if((pid_p
> PID_DEADZONE
) || (pid_p
< -PID_DEADZONE
))
954 pid_p
= pid_p
* PID_PCONST
;
957 if(battery_centivolts
< target_voltage
) {
959 pid_i
++; /* limit so it doesn't "wind up" */
963 pid_i
--; /* limit so it doesn't "wind up" */
967 trickle_sec
= pid_p
+ pid_i
;
969 if(trickle_sec
> 60) {
972 if(trickle_sec
< 0) {
976 } else if (charge_state
== DISCHARGING
) {
979 * The charger is enabled here only in one case: if it was
980 * turned on at boot time (power_init). Turn it off now.
983 charger_enable(false);
986 if (charger_input_state
== CHARGER_UNPLUGGED
) {
988 * The charger was just unplugged.
990 DEBUGF("power: charger disconnected, disabling\n");
992 charger_enable(false);
993 powermgmt_last_cycle_level
= battery_percent
;
994 powermgmt_last_cycle_startstop_min
= 0;
998 charge_state
= DISCHARGING
;
999 snprintf(power_message
, POWER_MESSAGE_LEN
, "Charger: discharge");
1002 #endif /* CONFIG_CHARGING == CHARGING_CONTROL */
1004 /* sleep for a minute */
1006 #if CONFIG_CHARGING == CHARGING_CONTROL
1007 if(trickle_sec
> 0) {
1008 charger_enable(true);
1009 power_thread_sleep(HZ
* trickle_sec
);
1011 if(trickle_sec
< 60)
1012 charger_enable(false);
1013 power_thread_sleep(HZ
* (60 - trickle_sec
));
1015 power_thread_sleep(HZ
* 60);
1018 #if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL)
1019 if(usb_inserted()) {
1021 /* It is probably too late to close the file but we can try...*/
1027 fd
= open(DEBUG_FILE_NAME
, O_WRONLY
| O_APPEND
| O_CREAT
);
1029 snprintf(debug_message
, DEBUG_MESSAGE_LEN
,
1030 "cycle_min, bat_centivolts, bat_percent, chgr_state, charge_state, pid_p, pid_i, trickle_sec\n");
1031 write(fd
, debug_message
, strlen(debug_message
));
1032 wrcount
= 99; /* force a flush */
1036 snprintf(debug_message
, DEBUG_MESSAGE_LEN
,
1037 "%d, %d, %d, %d, %d, %d, %d, %d\n",
1038 powermgmt_last_cycle_startstop_min
, battery_centivolts
,
1039 battery_percent
, charger_input_state
, charge_state
,
1040 pid_p
, pid_i
, trickle_sec
);
1041 write(fd
, debug_message
, strlen(debug_message
));
1046 handle_auto_poweroff();
1048 #if CONFIG_CHARGING == CHARGING_CONTROL
1049 powermgmt_last_cycle_startstop_min
++;
1054 void powermgmt_init(void)
1056 /* init history to 0 */
1057 memset(power_history
, 0x00, sizeof(power_history
));
1058 create_thread(power_thread
, power_stack
, sizeof(power_stack
),
1059 power_thread_name
IF_PRIO(, PRIORITY_SYSTEM
));
1062 #endif /* SIMULATOR */
1064 void sys_poweroff(void)
1066 logf("sys_poweroff()");
1067 /* If the main thread fails to shut down the system, we will force a
1068 power off after an 20 second timeout */
1069 shutdown_timeout
= HZ
*20;
1071 queue_post(&button_queue
, SYS_POWEROFF
, NULL
);
1074 void cancel_shutdown(void)
1076 logf("sys_cancel_shutdown()");
1078 #if defined(IAUDIO_X5) && !defined (SIMULATOR)
1079 /* TODO: Move some things to target/ tree */
1080 if (shutdown_timeout
)
1081 pcf50606_reset_timeout();
1084 shutdown_timeout
= 0;
1087 /* Various hardware housekeeping tasks relating to shutting down the jukebox */
1088 void shutdown_hw(void)
1091 #if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL)
1098 #ifdef HAVE_LCD_BITMAP
1103 while(ata_disk_is_active())
1109 #elif defined(HAVE_TLV320)
1111 #elif defined(HAVE_WM8758) || defined(HAVE_WM8975)
1115 #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
1116 backlight_set_fade_out(0);
1119 lcd_set_contrast(0);
1120 #endif /* IAUDIO_X5 */
1121 #ifdef HAVE_REMOTE_LCD
1122 remote_backlight_off();
1123 lcd_remote_set_contrast(0);
1126 #endif /* #ifndef SIMULATOR */