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"
35 #ifdef HAVE_REMOTE_LCD
36 #include "lcd-remote.h"
39 #include "backlight-target.h"
43 /* TODO: find a better way to do it but we need a kernel thread somewhere to
45 extern void screen_dump(void);
47 static inline void _backlight_on(void)
52 static inline void _backlight_off(void)
57 static inline void _backlight_set_brightness(int val
)
62 static inline void _buttonlight_on(void)
66 static inline void _buttonlight_off(void)
70 static inline void _buttonlight_set_brightness(int val
)
74 #ifdef HAVE_REMOTE_LCD
75 static inline void _remote_backlight_on(void)
77 sim_remote_backlight(100);
80 static inline void _remote_backlight_off(void)
82 sim_remote_backlight(0);
84 #endif /* HAVE_REMOTE_LCD */
86 #endif /* SIMULATOR */
88 #if defined(HAVE_BACKLIGHT) && !defined(BOOTLOADER)
93 #ifdef HAVE_REMOTE_LCD
97 #if defined(_BACKLIGHT_FADE_BOOST) || defined(_BACKLIGHT_FADE_ENABLE)
98 BACKLIGHT_FADE_FINISH
,
100 #ifdef HAVE_LCD_SLEEP
103 #ifdef HAVE_BUTTON_LIGHT
109 static void backlight_thread(void);
110 static long backlight_stack
[DEFAULT_STACK_SIZE
/sizeof(long)];
111 static const char backlight_thread_name
[] = "backlight";
112 static struct event_queue backlight_queue
;
114 static int backlight_timer
;
115 static int backlight_timeout
;
116 static int backlight_timeout_normal
= 5*HZ
;
118 static int backlight_timeout_plugged
= 5*HZ
;
120 #ifdef HAS_BUTTON_HOLD
121 static int backlight_on_button_hold
= 0;
124 #ifdef HAVE_BUTTON_LIGHT
125 static int buttonlight_timer
;
126 int _buttonlight_timeout
= 5*HZ
;
128 /* Update state of buttonlight according to timeout setting */
129 static void buttonlight_update_state(void)
131 buttonlight_timer
= _buttonlight_timeout
;
133 /* Buttonlight == OFF in the setting? */
134 if (buttonlight_timer
< 0)
136 buttonlight_timer
= 0; /* Disable the timeout */
143 /* external interface */
144 void buttonlight_on(void)
146 queue_remove_from_head(&backlight_queue
, BUTTON_LIGHT_ON
);
147 queue_post(&backlight_queue
, BUTTON_LIGHT_ON
, 0);
150 void buttonlight_off(void)
152 queue_post(&backlight_queue
, BUTTON_LIGHT_OFF
, 0);
155 void buttonlight_set_timeout(int value
)
157 _buttonlight_timeout
= HZ
* value
;
158 buttonlight_update_state();
163 #ifdef HAVE_REMOTE_LCD
164 static int remote_backlight_timer
;
165 static int remote_backlight_timeout
;
166 static int remote_backlight_timeout_normal
= 5*HZ
;
168 static int remote_backlight_timeout_plugged
= 5*HZ
;
170 #ifdef HAS_REMOTE_BUTTON_HOLD
171 static int remote_backlight_on_button_hold
= 0;
175 #ifdef HAVE_LCD_SLEEP
176 const signed char lcd_sleep_timeout_value
[10] =
178 -1, 0, 5, 10, 15, 20, 30, 45, 60, 90
180 int _lcd_sleep_timer
;
181 int _lcd_sleep_timeout
= 10*HZ
;
184 #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
185 /* backlight fading */
186 #define BL_PWM_INTERVAL 5 /* Cycle interval in ms */
187 #define BL_PWM_BITS 8
188 #define BL_PWM_COUNT (1<<BL_PWM_BITS)
190 /* s15.16 fixed point variables */
191 static int32_t bl_fade_in_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16)/300;
192 static int32_t bl_fade_out_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16)/2000;
193 static int32_t bl_dim_fraction
= 0;
195 static int bl_dim_target
= 0;
196 static int bl_dim_current
= 0;
197 static enum {DIM_STATE_START
, DIM_STATE_MAIN
} bl_dim_state
= DIM_STATE_START
;
198 static bool bl_timer_active
= false;
200 static void backlight_isr(void)
202 int timer_period
= (TIMER_FREQ
*BL_PWM_INTERVAL
/1000);
205 switch (bl_dim_state
)
208 case DIM_STATE_START
:
209 bl_dim_current
= bl_dim_fraction
>> 16;
211 if (bl_dim_current
> 0 && bl_dim_current
< BL_PWM_COUNT
)
214 timer_period
= (timer_period
* bl_dim_current
) >> BL_PWM_BITS
;
215 bl_dim_state
= DIM_STATE_MAIN
;
222 _backlight_off_isr();
223 if (bl_dim_current
== bl_dim_target
)
226 if (bl_dim_current
< bl_dim_target
)
228 bl_dim_fraction
= MIN(bl_dim_fraction
+ bl_fade_in_step
,
231 else if (bl_dim_current
> bl_dim_target
)
233 bl_dim_fraction
= MAX(bl_dim_fraction
- bl_fade_out_step
, 0);
237 /* Dim main screen */
239 _backlight_off_isr();
240 timer_period
= (timer_period
* (BL_PWM_COUNT
- bl_dim_current
))
242 bl_dim_state
= DIM_STATE_START
;
247 #if defined(_BACKLIGHT_FADE_BOOST) || defined(_BACKLIGHT_FADE_ENABLE)
248 queue_post(&backlight_queue
, BACKLIGHT_FADE_FINISH
, 0);
251 bl_timer_active
= false;
254 timer_set_period(timer_period
);
257 static void backlight_switch(void)
259 if (bl_dim_target
> (BL_PWM_COUNT
/2))
261 _backlight_on_normal();
262 bl_dim_fraction
= (BL_PWM_COUNT
<<16);
266 _backlight_off_normal();
271 static void backlight_release_timer(void)
273 #ifdef _BACKLIGHT_FADE_BOOST
277 bl_timer_active
= false;
281 static void backlight_dim(int value
)
283 /* protect from extraneous calls with the same target value */
284 if (value
== bl_dim_target
)
287 bl_dim_target
= value
;
292 if (timer_register(0, backlight_release_timer
, 2, 0, backlight_isr
))
294 #ifdef _BACKLIGHT_FADE_BOOST
295 /* Prevent cpu frequency changes while dimming. */
298 bl_timer_active
= true;
304 static void _backlight_on(void)
306 if (bl_fade_in_step
> 0)
308 #ifdef _BACKLIGHT_FADE_ENABLE
309 _backlight_hw_enable(true);
311 backlight_dim(BL_PWM_COUNT
);
315 bl_dim_target
= BL_PWM_COUNT
;
316 bl_dim_fraction
= (BL_PWM_COUNT
<<16);
317 _backlight_on_normal();
319 #ifdef HAVE_LCD_SLEEP
320 _lcd_sleep_timer
= 0; /* LCD should be awake already */
324 static void _backlight_off(void)
326 if (bl_fade_out_step
> 0)
332 bl_dim_target
= bl_dim_fraction
= 0;
333 _backlight_off_normal();
335 #ifdef HAVE_LCD_SLEEP
336 /* Start LCD sleep countdown */
337 if (_lcd_sleep_timeout
< 0)
339 _lcd_sleep_timer
= 0; /* Setting == Always */
343 _lcd_sleep_timer
= _lcd_sleep_timeout
;
347 void backlight_set_fade_in(int value
)
350 bl_fade_in_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16) / value
;
355 void backlight_set_fade_out(int value
)
358 bl_fade_out_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16) / value
;
360 bl_fade_out_step
= 0;
362 #endif /* defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR) */
364 /* Update state of backlight according to timeout setting */
365 static void backlight_update_state(void)
367 #ifdef HAS_BUTTON_HOLD
368 if ((backlight_on_button_hold
!= 0)
369 #ifdef HAVE_REMOTE_LCD_AS_MAIN
370 && remote_button_hold()
375 backlight_timeout
= (backlight_on_button_hold
== 2) ? 0 : -1;
376 /* always on or always off */
380 if (charger_inserted()
381 #ifdef HAVE_USB_POWER
385 backlight_timeout
= backlight_timeout_plugged
;
388 backlight_timeout
= backlight_timeout_normal
;
390 /* Backlight == OFF in the setting? */
391 if (backlight_timeout
< 0)
393 backlight_timer
= 0; /* Disable the timeout */
398 backlight_timer
= backlight_timeout
;
403 #ifdef HAVE_REMOTE_LCD
404 /* Update state of remote backlight according to timeout setting */
405 static void remote_backlight_update_state(void)
407 #ifdef HAS_REMOTE_BUTTON_HOLD
408 if (remote_button_hold() && (remote_backlight_on_button_hold
!= 0))
409 remote_backlight_timeout
= (remote_backlight_on_button_hold
== 2)
410 ? 0 : -1; /* always on or always off */
414 if (charger_inserted()
415 #ifdef HAVE_USB_POWER
419 remote_backlight_timeout
= remote_backlight_timeout_plugged
;
422 remote_backlight_timeout
= remote_backlight_timeout_normal
;
424 /* Backlight == OFF in the setting? */
425 if (remote_backlight_timeout
< 0)
427 remote_backlight_timer
= 0; /* Disable the timeout */
428 _remote_backlight_off();
432 remote_backlight_timer
= remote_backlight_timeout
;
433 _remote_backlight_on();
436 #endif /* HAVE_REMOTE_LCD */
438 void backlight_thread(void)
440 struct queue_event ev
;
445 queue_wait(&backlight_queue
, &ev
);
447 { /* These events must always be processed */
448 #ifdef _BACKLIGHT_FADE_BOOST
449 case BACKLIGHT_FADE_FINISH
:
453 #ifdef _BACKLIGHT_FADE_ENABLE
454 case BACKLIGHT_FADE_FINISH
:
455 _backlight_hw_enable((bl_dim_current
|bl_dim_target
) != 0);
460 /* Here for now or else the aggressive init messes up scrolling */
461 #ifdef HAVE_REMOTE_LCD
462 case SYS_REMOTE_PLUGGED
:
467 case SYS_REMOTE_UNPLUGGED
:
470 #elif defined HAVE_REMOTE_LCD_AS_MAIN
471 case SYS_REMOTE_PLUGGED
:
476 case SYS_REMOTE_UNPLUGGED
:
479 #endif /* HAVE_REMOTE_LCD/ HAVE_REMOTE_LCD_AS_MAIN */
480 #endif /* !SIMULATOR */
482 /* This one here too for lack of a better place */
487 case SYS_USB_CONNECTED
:
488 /* Tell the USB thread that we are safe */
489 DEBUGF("backlight_thread got SYS_USB_CONNECTED\n");
490 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
493 case SYS_USB_DISCONNECTED
:
494 usb_acknowledge(SYS_USB_DISCONNECTED_ACK
);
501 { /* These events are only processed if backlight isn't locked */
502 #ifdef HAVE_REMOTE_LCD
503 case REMOTE_BACKLIGHT_ON
:
504 remote_backlight_update_state();
507 case REMOTE_BACKLIGHT_OFF
:
508 remote_backlight_timer
= 0; /* Disable the timeout */
509 _remote_backlight_off();
511 #endif /* HAVE_REMOTE_LCD */
514 backlight_update_state();
518 backlight_timer
= 0; /* Disable the timeout */
522 #ifdef HAVE_LCD_SLEEP
527 #ifdef HAVE_BUTTON_LIGHT
528 case BUTTON_LIGHT_ON
:
529 buttonlight_update_state();
532 case BUTTON_LIGHT_OFF
:
533 buttonlight_timer
= 0;
538 case SYS_POWEROFF
: /* Lock backlight on poweroff so it doesn't */
539 locked
= true; /* go off before power is actually cut. */
542 case SYS_CHARGER_CONNECTED
:
543 case SYS_CHARGER_DISCONNECTED
:
545 backlight_update_state();
546 #ifdef HAVE_REMOTE_LCD
547 remote_backlight_update_state();
554 static void backlight_tick(void)
559 if(backlight_timer
== 0)
564 #ifdef HAVE_LCD_SLEEP
565 else if(_lcd_sleep_timer
)
568 if(_lcd_sleep_timer
== 0)
570 /* Queue on bl thread or freeze! */
571 queue_post(&backlight_queue
, LCD_SLEEP
, 0);
574 #endif /* HAVE_LCD_SLEEP */
576 #ifdef HAVE_REMOTE_LCD
577 if(remote_backlight_timer
)
579 remote_backlight_timer
--;
580 if(remote_backlight_timer
== 0)
582 remote_backlight_off();
585 #endif /* HAVE_REMOVE_LCD */
586 #ifdef HAVE_BUTTON_LIGHT
587 if (buttonlight_timer
)
590 if (buttonlight_timer
== 0)
595 #endif /* HAVE_BUTTON_LIGHT */
598 void backlight_init(void)
600 queue_init(&backlight_queue
, true);
603 if (_backlight_init())
605 # ifdef HAVE_BACKLIGHT_PWM_FADING
606 /* If backlight is already on, don't fade in. */
607 bl_dim_target
= BL_PWM_COUNT
;
608 bl_dim_fraction
= (BL_PWM_COUNT
<<16);
612 /* Leave all lights as set by the bootloader here. The settings load will
613 * call the appropriate backlight_set_*() functions, only changing light
614 * status if necessary. */
616 create_thread(backlight_thread
, backlight_stack
,
617 sizeof(backlight_stack
), 0, backlight_thread_name
618 IF_PRIO(, PRIORITY_USER_INTERFACE
)
620 tick_add_task(backlight_tick
);
623 void backlight_on(void)
625 queue_remove_from_head(&backlight_queue
, BACKLIGHT_ON
);
626 queue_post(&backlight_queue
, BACKLIGHT_ON
, 0);
629 void backlight_off(void)
631 queue_post(&backlight_queue
, BACKLIGHT_OFF
, 0);
634 /* returns true when the backlight is on OR when it's set to always off */
635 bool is_backlight_on(void)
637 if (backlight_timer
|| backlight_timeout
<= 0)
643 /* return value in ticks; 0 means always on, <0 means always off */
644 int backlight_get_current_timeout(void)
646 return backlight_timeout
;
649 void backlight_set_timeout(int value
)
651 backlight_timeout_normal
= HZ
* value
;
652 backlight_update_state();
656 void backlight_set_timeout_plugged(int value
)
658 backlight_timeout_plugged
= HZ
* value
;
659 backlight_update_state();
661 #endif /* CONFIG_CHARGING */
663 #ifdef HAS_BUTTON_HOLD
664 /* Hold button change event handler. */
665 void backlight_hold_changed(bool hold_button
)
667 if (!hold_button
|| (backlight_on_button_hold
> 0))
668 /* if unlocked or override in effect */
672 void backlight_set_on_button_hold(int index
)
674 if ((unsigned)index
>= 3)
675 /* if given a weird value, use default */
678 backlight_on_button_hold
= index
;
679 backlight_update_state();
681 #endif /* HAS_BUTTON_HOLD */
683 #ifdef HAVE_LCD_SLEEP
684 void lcd_set_sleep_after_backlight_off(int index
)
686 if ((unsigned)index
>= sizeof(lcd_sleep_timeout_value
))
687 /* if given a weird value, use default */
690 _lcd_sleep_timeout
= HZ
* lcd_sleep_timeout_value
[index
];
692 if (backlight_timer
> 0 || backlight_get_current_timeout() == 0)
693 /* Timer will be set when bl turns off or bl set to on. */
696 /* Backlight is Off */
697 if (_lcd_sleep_timeout
< 0)
698 _lcd_sleep_timer
= 1; /* Always - sleep next tick */
700 _lcd_sleep_timer
= _lcd_sleep_timeout
; /* Never, other */
702 #endif /* HAVE_LCD_SLEEP */
704 #ifdef HAVE_REMOTE_LCD
705 void remote_backlight_on(void)
707 queue_post(&backlight_queue
, REMOTE_BACKLIGHT_ON
, 0);
710 void remote_backlight_off(void)
712 queue_post(&backlight_queue
, REMOTE_BACKLIGHT_OFF
, 0);
715 void remote_backlight_set_timeout(int value
)
717 remote_backlight_timeout_normal
= HZ
* value
;
718 remote_backlight_update_state();
722 void remote_backlight_set_timeout_plugged(int value
)
724 remote_backlight_timeout_plugged
= HZ
* value
;
725 remote_backlight_update_state();
727 #endif /* CONFIG_CHARGING */
729 #ifdef HAS_REMOTE_BUTTON_HOLD
730 /* Remote hold button change event handler. */
731 void remote_backlight_hold_changed(bool rc_hold_button
)
733 if (!rc_hold_button
|| (remote_backlight_on_button_hold
> 0))
734 /* if unlocked or override */
735 remote_backlight_on();
738 void remote_backlight_set_on_button_hold(int index
)
740 if ((unsigned)index
>= 3)
741 /* if given a weird value, use default */
744 remote_backlight_on_button_hold
= index
;
745 remote_backlight_update_state();
747 #endif /* HAS_REMOTE_BUTTON_HOLD */
749 /* return value in ticks; 0 means always on, <0 means always off */
750 int remote_backlight_get_current_timeout(void)
752 return remote_backlight_timeout
;
755 /* returns true when the backlight is on OR when it's set to always off */
756 bool is_remote_backlight_on(void)
758 if (remote_backlight_timer
!= 0 || remote_backlight_timeout
<= 0)
764 #endif /* HAVE_REMOTE_LCD */
766 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
767 void backlight_set_brightness(int val
)
769 if (val
< MIN_BRIGHTNESS_SETTING
)
770 val
= MIN_BRIGHTNESS_SETTING
;
771 else if (val
> MAX_BRIGHTNESS_SETTING
)
772 val
= MAX_BRIGHTNESS_SETTING
;
774 _backlight_set_brightness(val
);
776 #endif /* HAVE_BACKLIGHT_BRIGHTNESS */
778 #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
779 void buttonlight_set_brightness(int val
)
781 if (val
< MIN_BRIGHTNESS_SETTING
)
782 val
= MIN_BRIGHTNESS_SETTING
;
783 else if (val
> MAX_BRIGHTNESS_SETTING
)
784 val
= MAX_BRIGHTNESS_SETTING
;
786 _buttonlight_set_brightness(val
);
788 #endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */
790 #else /* !defined(HAVE_BACKLIGHT) || defined(BOOTLOADER)
791 -- no backlight, empty dummy functions */
793 #if defined(BOOTLOADER) && defined(HAVE_BACKLIGHT)
794 void backlight_init(void)
796 (void)_backlight_init();
801 void backlight_on(void) {}
802 void backlight_off(void) {}
803 void buttonlight_on(void) {}
804 void backlight_set_timeout(int value
) {(void)value
;}
805 bool is_backlight_on(void) {return true;}
806 #ifdef HAVE_REMOTE_LCD
807 void remote_backlight_on(void) {}
808 void remote_backlight_off(void) {}
809 void remote_backlight_set_timeout(int value
) {(void)value
;}
810 bool is_remote_backlight_on(void) {return true;}
811 #endif /* HAVE_REMOTE_LCD */
812 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
813 void backlight_set_brightness(int val
) { (void)val
; }
815 #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
816 void buttonlight_set_brightness(int val
) { (void)val
; }
818 #endif /* defined(HAVE_BACKLIGHT) && !defined(BOOTLOADER) */