1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
32 #include "backlight.h"
34 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
35 #include "lcd.h" /* for lcd_enable() and lcd_sleep() */
37 #ifdef HAVE_REMOTE_LCD
38 #include "lcd-remote.h"
41 #include "backlight-target.h"
45 /* TODO: find a better way to do it but we need a kernel thread somewhere to
47 extern void screen_dump(void);
49 static inline void _backlight_on(void)
54 static inline void _backlight_off(void)
59 static inline void _backlight_set_brightness(int val
)
64 static inline void _buttonlight_on(void)
68 static inline void _buttonlight_off(void)
72 static inline void _buttonlight_set_brightness(int val
)
76 #ifdef HAVE_REMOTE_LCD
77 static inline void _remote_backlight_on(void)
79 sim_remote_backlight(100);
82 static inline void _remote_backlight_off(void)
84 sim_remote_backlight(0);
86 #endif /* HAVE_REMOTE_LCD */
88 #endif /* SIMULATOR */
90 #if defined(HAVE_BACKLIGHT) && !defined(BOOTLOADER)
95 #ifdef HAVE_REMOTE_LCD
99 #if defined(_BACKLIGHT_FADE_BOOST) || defined(_BACKLIGHT_FADE_ENABLE)
100 BACKLIGHT_FADE_FINISH
,
102 #ifdef HAVE_LCD_SLEEP
105 #ifdef HAVE_BUTTON_LIGHT
111 static void backlight_thread(void);
112 static long backlight_stack
[DEFAULT_STACK_SIZE
/sizeof(long)];
113 static const char backlight_thread_name
[] = "backlight";
114 static struct event_queue backlight_queue
;
116 static int backlight_timer
;
117 static int backlight_timeout
;
118 static int backlight_timeout_normal
= 5*HZ
;
120 static int backlight_timeout_plugged
= 5*HZ
;
122 #ifdef HAS_BUTTON_HOLD
123 static int backlight_on_button_hold
= 0;
126 #ifdef HAVE_BUTTON_LIGHT
127 static int buttonlight_timer
;
128 int _buttonlight_timeout
= 5*HZ
;
130 /* Update state of buttonlight according to timeout setting */
131 static void buttonlight_update_state(void)
133 buttonlight_timer
= _buttonlight_timeout
;
135 /* Buttonlight == OFF in the setting? */
136 if (buttonlight_timer
< 0)
138 buttonlight_timer
= 0; /* Disable the timeout */
145 /* external interface */
146 void buttonlight_on(void)
148 queue_remove_from_head(&backlight_queue
, BUTTON_LIGHT_ON
);
149 queue_post(&backlight_queue
, BUTTON_LIGHT_ON
, 0);
152 void buttonlight_off(void)
154 queue_post(&backlight_queue
, BUTTON_LIGHT_OFF
, 0);
157 void buttonlight_set_timeout(int value
)
159 _buttonlight_timeout
= HZ
* value
;
160 buttonlight_update_state();
165 #ifdef HAVE_REMOTE_LCD
166 static int remote_backlight_timer
;
167 static int remote_backlight_timeout
;
168 static int remote_backlight_timeout_normal
= 5*HZ
;
170 static int remote_backlight_timeout_plugged
= 5*HZ
;
172 #ifdef HAS_REMOTE_BUTTON_HOLD
173 static int remote_backlight_on_button_hold
= 0;
177 #ifdef HAVE_LCD_SLEEP
178 const signed char lcd_sleep_timeout_value
[10] =
180 -1, 0, 5, 10, 15, 20, 30, 45, 60, 90
182 int _lcd_sleep_timer
;
183 int _lcd_sleep_timeout
= 10*HZ
;
186 #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
187 /* backlight fading */
188 #define BL_PWM_INTERVAL 5 /* Cycle interval in ms */
189 #define BL_PWM_BITS 8
190 #define BL_PWM_COUNT (1<<BL_PWM_BITS)
192 /* s15.16 fixed point variables */
193 static int32_t bl_fade_in_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16)/300;
194 static int32_t bl_fade_out_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16)/2000;
195 static int32_t bl_dim_fraction
= 0;
197 static int bl_dim_target
= 0;
198 static int bl_dim_current
= 0;
199 static enum {DIM_STATE_START
, DIM_STATE_MAIN
} bl_dim_state
= DIM_STATE_START
;
200 static bool bl_timer_active
= false;
202 static void backlight_isr(void)
204 int timer_period
= (TIMER_FREQ
*BL_PWM_INTERVAL
/1000);
207 switch (bl_dim_state
)
210 case DIM_STATE_START
:
211 bl_dim_current
= bl_dim_fraction
>> 16;
213 if (bl_dim_current
> 0 && bl_dim_current
< BL_PWM_COUNT
)
216 timer_period
= (timer_period
* bl_dim_current
) >> BL_PWM_BITS
;
217 bl_dim_state
= DIM_STATE_MAIN
;
224 _backlight_off_isr();
225 if (bl_dim_current
== bl_dim_target
)
228 if (bl_dim_current
< bl_dim_target
)
230 bl_dim_fraction
= MIN(bl_dim_fraction
+ bl_fade_in_step
,
233 else if (bl_dim_current
> bl_dim_target
)
235 bl_dim_fraction
= MAX(bl_dim_fraction
- bl_fade_out_step
, 0);
239 /* Dim main screen */
241 _backlight_off_isr();
242 timer_period
= (timer_period
* (BL_PWM_COUNT
- bl_dim_current
))
244 bl_dim_state
= DIM_STATE_START
;
249 #if defined(_BACKLIGHT_FADE_BOOST) || defined(_BACKLIGHT_FADE_ENABLE)
250 queue_post(&backlight_queue
, BACKLIGHT_FADE_FINISH
, 0);
253 bl_timer_active
= false;
256 timer_set_period(timer_period
);
259 static void backlight_switch(void)
261 if (bl_dim_target
> (BL_PWM_COUNT
/2))
263 _backlight_on_normal();
264 bl_dim_fraction
= (BL_PWM_COUNT
<<16);
268 _backlight_off_normal();
273 static void backlight_release_timer(void)
275 #ifdef _BACKLIGHT_FADE_BOOST
279 bl_timer_active
= false;
283 static void backlight_dim(int value
)
285 /* protect from extraneous calls with the same target value */
286 if (value
== bl_dim_target
)
289 bl_dim_target
= value
;
294 if (timer_register(0, backlight_release_timer
, 2, 0, backlight_isr
))
296 #ifdef _BACKLIGHT_FADE_BOOST
297 /* Prevent cpu frequency changes while dimming. */
300 bl_timer_active
= true;
306 static void _backlight_on(void)
308 if (bl_fade_in_step
> 0)
310 #ifdef _BACKLIGHT_FADE_ENABLE
311 _backlight_hw_enable(true);
313 backlight_dim(BL_PWM_COUNT
);
317 bl_dim_target
= BL_PWM_COUNT
;
318 bl_dim_fraction
= (BL_PWM_COUNT
<<16);
319 _backlight_on_normal();
321 #ifdef HAVE_LCD_SLEEP
322 _lcd_sleep_timer
= 0; /* LCD should be awake already */
326 static void _backlight_off(void)
328 if (bl_fade_out_step
> 0)
334 bl_dim_target
= bl_dim_fraction
= 0;
335 _backlight_off_normal();
337 #ifdef HAVE_LCD_SLEEP
338 /* Start LCD sleep countdown */
339 if (_lcd_sleep_timeout
< 0)
341 _lcd_sleep_timer
= 0; /* Setting == Always */
345 _lcd_sleep_timer
= _lcd_sleep_timeout
;
349 void backlight_set_fade_in(int value
)
352 bl_fade_in_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16) / value
;
357 void backlight_set_fade_out(int value
)
360 bl_fade_out_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16) / value
;
362 bl_fade_out_step
= 0;
364 #endif /* defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR) */
366 /* Update state of backlight according to timeout setting */
367 static void backlight_update_state(void)
369 #ifdef HAS_BUTTON_HOLD
370 if (button_hold() && (backlight_on_button_hold
!= 0))
371 backlight_timeout
= (backlight_on_button_hold
== 2) ? 0 : -1;
372 /* always on or always off */
376 if (charger_inserted()
377 #ifdef HAVE_USB_POWER
381 backlight_timeout
= backlight_timeout_plugged
;
384 backlight_timeout
= backlight_timeout_normal
;
386 /* Backlight == OFF in the setting? */
387 if (backlight_timeout
< 0)
389 backlight_timer
= 0; /* Disable the timeout */
394 backlight_timer
= backlight_timeout
;
399 #ifdef HAVE_REMOTE_LCD
400 /* Update state of remote backlight according to timeout setting */
401 static void remote_backlight_update_state(void)
403 #ifdef HAS_REMOTE_BUTTON_HOLD
404 if (remote_button_hold() && (remote_backlight_on_button_hold
!= 0))
405 remote_backlight_timeout
= (remote_backlight_on_button_hold
== 2)
406 ? 0 : -1; /* always on or always off */
410 if (charger_inserted()
411 #ifdef HAVE_USB_POWER
415 remote_backlight_timeout
= remote_backlight_timeout_plugged
;
418 remote_backlight_timeout
= remote_backlight_timeout_normal
;
420 /* Backlight == OFF in the setting? */
421 if (remote_backlight_timeout
< 0)
423 remote_backlight_timer
= 0; /* Disable the timeout */
424 _remote_backlight_off();
428 remote_backlight_timer
= remote_backlight_timeout
;
429 _remote_backlight_on();
432 #endif /* HAVE_REMOTE_LCD */
434 void backlight_thread(void)
436 struct queue_event ev
;
441 queue_wait(&backlight_queue
, &ev
);
443 { /* These events must always be processed */
444 #ifdef _BACKLIGHT_FADE_BOOST
445 case BACKLIGHT_FADE_FINISH
:
449 #ifdef _BACKLIGHT_FADE_ENABLE
450 case BACKLIGHT_FADE_FINISH
:
451 _backlight_hw_enable((bl_dim_current
|bl_dim_target
) != 0);
455 #if defined(HAVE_REMOTE_LCD) && !defined(SIMULATOR)
456 /* Here for now or else the aggressive init messes up scrolling */
457 case SYS_REMOTE_PLUGGED
:
462 case SYS_REMOTE_UNPLUGGED
:
465 #endif /* defined(HAVE_REMOTE_LCD) && !defined(SIMULATOR) */
467 /* This one here too for lack of a better place */
472 case SYS_USB_CONNECTED
:
473 /* Tell the USB thread that we are safe */
474 DEBUGF("backlight_thread got SYS_USB_CONNECTED\n");
475 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
478 case SYS_USB_DISCONNECTED
:
479 usb_acknowledge(SYS_USB_DISCONNECTED_ACK
);
486 { /* These events are only processed if backlight isn't locked */
487 #ifdef HAVE_REMOTE_LCD
488 case REMOTE_BACKLIGHT_ON
:
489 remote_backlight_update_state();
492 case REMOTE_BACKLIGHT_OFF
:
493 remote_backlight_timer
= 0; /* Disable the timeout */
494 _remote_backlight_off();
496 #endif /* HAVE_REMOTE_LCD */
499 backlight_update_state();
503 backlight_timer
= 0; /* Disable the timeout */
507 #ifdef HAVE_LCD_SLEEP
512 #ifdef HAVE_BUTTON_LIGHT
513 case BUTTON_LIGHT_ON
:
514 buttonlight_update_state();
517 case BUTTON_LIGHT_OFF
:
518 buttonlight_timer
= 0;
523 case SYS_POWEROFF
: /* Lock backlight on poweroff so it doesn't */
524 locked
= true; /* go off before power is actually cut. */
527 case SYS_CHARGER_CONNECTED
:
528 case SYS_CHARGER_DISCONNECTED
:
530 backlight_update_state();
531 #ifdef HAVE_REMOTE_LCD
532 remote_backlight_update_state();
539 static void backlight_tick(void)
544 if(backlight_timer
== 0)
549 #ifdef HAVE_LCD_SLEEP
550 else if(_lcd_sleep_timer
)
553 if(_lcd_sleep_timer
== 0)
555 /* Queue on bl thread or freeze! */
556 queue_post(&backlight_queue
, LCD_SLEEP
, 0);
559 #endif /* HAVE_LCD_SLEEP */
561 #ifdef HAVE_REMOTE_LCD
562 if(remote_backlight_timer
)
564 remote_backlight_timer
--;
565 if(remote_backlight_timer
== 0)
567 remote_backlight_off();
570 #endif /* HAVE_REMOVE_LCD */
571 #ifdef HAVE_BUTTON_LIGHT
572 if (buttonlight_timer
)
575 if (buttonlight_timer
== 0)
580 #endif /* HAVE_BUTTON_LIGHT */
583 void backlight_init(void)
585 queue_init(&backlight_queue
, true);
588 if (_backlight_init())
590 # ifdef HAVE_BACKLIGHT_PWM_FADING
591 /* If backlight is already on, don't fade in. */
592 bl_dim_target
= BL_PWM_COUNT
;
593 bl_dim_fraction
= (BL_PWM_COUNT
<<16);
597 /* Leave all lights as set by the bootloader here. The settings load will
598 * call the appropriate backlight_set_*() functions, only changing light
599 * status if necessary. */
601 create_thread(backlight_thread
, backlight_stack
,
602 sizeof(backlight_stack
), 0, backlight_thread_name
603 IF_PRIO(, PRIORITY_USER_INTERFACE
)
605 tick_add_task(backlight_tick
);
608 void backlight_on(void)
610 queue_remove_from_head(&backlight_queue
, BACKLIGHT_ON
);
611 queue_post(&backlight_queue
, BACKLIGHT_ON
, 0);
614 void backlight_off(void)
616 queue_post(&backlight_queue
, BACKLIGHT_OFF
, 0);
619 /* returns true when the backlight is on OR when it's set to always off */
620 bool is_backlight_on(void)
622 if (backlight_timer
|| backlight_timeout
<= 0)
628 /* return value in ticks; 0 means always on, <0 means always off */
629 int backlight_get_current_timeout(void)
631 return backlight_timeout
;
634 void backlight_set_timeout(int value
)
636 backlight_timeout_normal
= HZ
* value
;
637 backlight_update_state();
641 void backlight_set_timeout_plugged(int value
)
643 backlight_timeout_plugged
= HZ
* value
;
644 backlight_update_state();
646 #endif /* CONFIG_CHARGING */
648 #ifdef HAS_BUTTON_HOLD
649 /* Hold button change event handler. */
650 void backlight_hold_changed(bool hold_button
)
652 if (!hold_button
|| (backlight_on_button_hold
> 0))
653 /* if unlocked or override in effect */
657 void backlight_set_on_button_hold(int index
)
659 if ((unsigned)index
>= 3)
660 /* if given a weird value, use default */
663 backlight_on_button_hold
= index
;
664 backlight_update_state();
666 #endif /* HAS_BUTTON_HOLD */
668 #ifdef HAVE_LCD_SLEEP
669 void lcd_set_sleep_after_backlight_off(int index
)
671 if ((unsigned)index
>= sizeof(lcd_sleep_timeout_value
))
672 /* if given a weird value, use default */
675 _lcd_sleep_timeout
= HZ
* lcd_sleep_timeout_value
[index
];
677 if (backlight_timer
> 0 || backlight_get_current_timeout() == 0)
678 /* Timer will be set when bl turns off or bl set to on. */
681 /* Backlight is Off */
682 if (_lcd_sleep_timeout
< 0)
683 _lcd_sleep_timer
= 1; /* Always - sleep next tick */
685 _lcd_sleep_timer
= _lcd_sleep_timeout
; /* Never, other */
687 #endif /* HAVE_LCD_SLEEP */
689 #ifdef HAVE_REMOTE_LCD
690 void remote_backlight_on(void)
692 queue_post(&backlight_queue
, REMOTE_BACKLIGHT_ON
, 0);
695 void remote_backlight_off(void)
697 queue_post(&backlight_queue
, REMOTE_BACKLIGHT_OFF
, 0);
700 void remote_backlight_set_timeout(int value
)
702 remote_backlight_timeout_normal
= HZ
* value
;
703 remote_backlight_update_state();
707 void remote_backlight_set_timeout_plugged(int value
)
709 remote_backlight_timeout_plugged
= HZ
* value
;
710 remote_backlight_update_state();
712 #endif /* CONFIG_CHARGING */
714 #ifdef HAS_REMOTE_BUTTON_HOLD
715 /* Remote hold button change event handler. */
716 void remote_backlight_hold_changed(bool rc_hold_button
)
718 if (!rc_hold_button
|| (remote_backlight_on_button_hold
> 0))
719 /* if unlocked or override */
720 remote_backlight_on();
723 void remote_backlight_set_on_button_hold(int index
)
725 if ((unsigned)index
>= 3)
726 /* if given a weird value, use default */
729 remote_backlight_on_button_hold
= index
;
730 remote_backlight_update_state();
732 #endif /* HAS_REMOTE_BUTTON_HOLD */
734 /* return value in ticks; 0 means always on, <0 means always off */
735 int remote_backlight_get_current_timeout(void)
737 return remote_backlight_timeout
;
740 /* returns true when the backlight is on OR when it's set to always off */
741 bool is_remote_backlight_on(void)
743 if (remote_backlight_timer
!= 0 || remote_backlight_timeout
<= 0)
749 #endif /* HAVE_REMOTE_LCD */
751 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
752 void backlight_set_brightness(int val
)
754 if (val
< MIN_BRIGHTNESS_SETTING
)
755 val
= MIN_BRIGHTNESS_SETTING
;
756 else if (val
> MAX_BRIGHTNESS_SETTING
)
757 val
= MAX_BRIGHTNESS_SETTING
;
759 _backlight_set_brightness(val
);
761 #endif /* HAVE_BACKLIGHT_BRIGHTNESS */
763 #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
764 void buttonlight_set_brightness(int val
)
766 if (val
< MIN_BRIGHTNESS_SETTING
)
767 val
= MIN_BRIGHTNESS_SETTING
;
768 else if (val
> MAX_BRIGHTNESS_SETTING
)
769 val
= MAX_BRIGHTNESS_SETTING
;
771 _buttonlight_set_brightness(val
);
773 #endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */
775 #else /* !defined(HAVE_BACKLIGHT) || defined(BOOTLOADER)
776 -- no backlight, empty dummy functions */
778 #if defined(BOOTLOADER) && defined(HAVE_BACKLIGHT)
779 void backlight_init(void)
781 (void)_backlight_init();
786 void backlight_on(void) {}
787 void backlight_off(void) {}
788 void buttonlight_on(void) {}
789 void backlight_set_timeout(int value
) {(void)value
;}
790 bool is_backlight_on(void) {return true;}
791 #ifdef HAVE_REMOTE_LCD
792 void remote_backlight_on(void) {}
793 void remote_backlight_off(void) {}
794 void remote_backlight_set_timeout(int value
) {(void)value
;}
795 bool is_remote_backlight_on(void) {return true;}
796 #endif /* HAVE_REMOTE_LCD */
797 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
798 void backlight_set_brightness(int val
) { (void)val
; }
800 #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
801 void buttonlight_set_brightness(int val
) { (void)val
; }
803 #endif /* defined(HAVE_BACKLIGHT) && !defined(BOOTLOADER) */