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"
42 #if !defined(BOOTLOADER)
43 /* The whole driver should be built */
44 #define BACKLIGHT_FULL_INIT
48 /* TODO: find a better way to do it but we need a kernel thread somewhere to
50 extern void screen_dump(void);
52 static inline void _backlight_on(void)
57 static inline void _backlight_off(void)
62 static inline void _backlight_set_brightness(int val
)
67 static inline void _buttonlight_on(void)
71 static inline void _buttonlight_off(void)
75 static inline void _buttonlight_set_brightness(int val
)
79 #ifdef HAVE_REMOTE_LCD
80 static inline void _remote_backlight_on(void)
82 sim_remote_backlight(100);
85 static inline void _remote_backlight_off(void)
87 sim_remote_backlight(0);
89 #endif /* HAVE_REMOTE_LCD */
91 #endif /* SIMULATOR */
93 #if defined(HAVE_BACKLIGHT) && defined(BACKLIGHT_FULL_INIT)
98 #ifdef HAVE_REMOTE_LCD
100 REMOTE_BACKLIGHT_OFF
,
102 #if defined(_BACKLIGHT_FADE_BOOST) || defined(_BACKLIGHT_FADE_ENABLE)
103 BACKLIGHT_FADE_FINISH
,
105 #ifdef HAVE_LCD_SLEEP
108 #ifdef HAVE_BUTTON_LIGHT
112 #ifdef BACKLIGHT_DRIVER_CLOSE
117 static void backlight_thread(void);
118 static long backlight_stack
[DEFAULT_STACK_SIZE
/sizeof(long)];
119 static const char backlight_thread_name
[] = "backlight";
120 static struct event_queue backlight_queue
;
121 #ifdef BACKLIGHT_DRIVER_CLOSE
122 static struct thread_entry
*backlight_thread_p
= NULL
;
125 static int backlight_timer SHAREDBSS_ATTR
;
126 static int backlight_timeout SHAREDBSS_ATTR
;
127 static int backlight_timeout_normal
= 5*HZ
;
129 static int backlight_timeout_plugged
= 5*HZ
;
131 #ifdef HAS_BUTTON_HOLD
132 static int backlight_on_button_hold
= 0;
135 #ifdef HAVE_BUTTON_LIGHT
136 static int buttonlight_timer
;
137 int _buttonlight_timeout
= 5*HZ
;
139 /* Update state of buttonlight according to timeout setting */
140 static void buttonlight_update_state(void)
142 buttonlight_timer
= _buttonlight_timeout
;
144 /* Buttonlight == OFF in the setting? */
145 if (buttonlight_timer
< 0)
147 buttonlight_timer
= 0; /* Disable the timeout */
154 /* external interface */
155 void buttonlight_on(void)
157 queue_remove_from_head(&backlight_queue
, BUTTON_LIGHT_ON
);
158 queue_post(&backlight_queue
, BUTTON_LIGHT_ON
, 0);
161 void buttonlight_off(void)
163 queue_post(&backlight_queue
, BUTTON_LIGHT_OFF
, 0);
166 void buttonlight_set_timeout(int value
)
168 _buttonlight_timeout
= HZ
* value
;
169 buttonlight_update_state();
172 #endif /* HAVE_BUTTON_LIGHT */
174 #ifdef HAVE_REMOTE_LCD
175 static int remote_backlight_timer
;
176 static int remote_backlight_timeout
;
177 static int remote_backlight_timeout_normal
= 5*HZ
;
179 static int remote_backlight_timeout_plugged
= 5*HZ
;
181 #ifdef HAS_REMOTE_BUTTON_HOLD
182 static int remote_backlight_on_button_hold
= 0;
184 #endif /* HAVE_REMOTE_LCD */
186 #ifdef HAVE_LCD_SLEEP
187 #ifdef HAVE_LCD_SLEEP_SETTING
188 const signed char lcd_sleep_timeout_value
[10] =
190 -1, 0, 5, 10, 15, 20, 30, 45, 60, 90
192 static int lcd_sleep_timeout
= 10*HZ
;
194 /* Target defines needed value */
195 static const int lcd_sleep_timeout
= LCD_SLEEP_TIMEOUT
;
198 static int lcd_sleep_timer
= 0;
200 void backlight_lcd_sleep_countdown(bool start
)
204 /* Cancel the LCD sleep countdown */
209 /* Start LCD sleep countdown */
210 if (lcd_sleep_timeout
< 0)
212 lcd_sleep_timer
= 0; /* Setting == Always */
217 lcd_sleep_timer
= lcd_sleep_timeout
;
220 #endif /* HAVE_LCD_SLEEP */
222 #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
223 /* backlight fading */
224 #define BL_PWM_INTERVAL 5 /* Cycle interval in ms */
225 #define BL_PWM_BITS 8
226 #define BL_PWM_COUNT (1<<BL_PWM_BITS)
228 /* s15.16 fixed point variables */
229 static int32_t bl_fade_in_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16)/300;
230 static int32_t bl_fade_out_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16)/2000;
231 static int32_t bl_dim_fraction
= 0;
233 static int bl_dim_target
= 0;
234 static int bl_dim_current
= 0;
235 static enum {DIM_STATE_START
, DIM_STATE_MAIN
} bl_dim_state
= DIM_STATE_START
;
236 static bool bl_timer_active
= false;
238 static void backlight_isr(void)
240 int timer_period
= (TIMER_FREQ
*BL_PWM_INTERVAL
/1000);
243 switch (bl_dim_state
)
246 case DIM_STATE_START
:
247 bl_dim_current
= bl_dim_fraction
>> 16;
249 if (bl_dim_current
> 0 && bl_dim_current
< BL_PWM_COUNT
)
252 timer_period
= (timer_period
* bl_dim_current
) >> BL_PWM_BITS
;
253 bl_dim_state
= DIM_STATE_MAIN
;
260 _backlight_off_isr();
261 if (bl_dim_current
== bl_dim_target
)
264 if (bl_dim_current
< bl_dim_target
)
266 bl_dim_fraction
= MIN(bl_dim_fraction
+ bl_fade_in_step
,
269 else if (bl_dim_current
> bl_dim_target
)
271 bl_dim_fraction
= MAX(bl_dim_fraction
- bl_fade_out_step
, 0);
275 /* Dim main screen */
277 _backlight_off_isr();
278 timer_period
= (timer_period
* (BL_PWM_COUNT
- bl_dim_current
))
280 bl_dim_state
= DIM_STATE_START
;
285 #if defined(_BACKLIGHT_FADE_BOOST) || defined(_BACKLIGHT_FADE_ENABLE)
286 queue_post(&backlight_queue
, BACKLIGHT_FADE_FINISH
, 0);
289 bl_timer_active
= false;
292 timer_set_period(timer_period
);
295 static void backlight_switch(void)
297 if (bl_dim_target
> (BL_PWM_COUNT
/2))
299 _backlight_on_normal();
300 bl_dim_fraction
= (BL_PWM_COUNT
<<16);
304 _backlight_off_normal();
309 static void backlight_release_timer(void)
311 #ifdef _BACKLIGHT_FADE_BOOST
315 bl_timer_active
= false;
319 static void backlight_dim(int value
)
321 /* protect from extraneous calls with the same target value */
322 if (value
== bl_dim_target
)
325 bl_dim_target
= value
;
330 if (timer_register(0, backlight_release_timer
, 2, 0, backlight_isr
333 #ifdef _BACKLIGHT_FADE_BOOST
334 /* Prevent cpu frequency changes while dimming. */
337 bl_timer_active
= true;
343 static void _backlight_on(void)
345 #ifdef HAVE_LCD_SLEEP
346 backlight_lcd_sleep_countdown(false);
349 if (bl_fade_in_step
> 0)
351 #ifdef _BACKLIGHT_FADE_ENABLE
352 _backlight_hw_enable(true);
354 backlight_dim(BL_PWM_COUNT
);
358 bl_dim_target
= BL_PWM_COUNT
;
359 bl_dim_fraction
= (BL_PWM_COUNT
<<16);
360 _backlight_on_normal();
364 static void _backlight_off(void)
366 if (bl_fade_out_step
> 0)
372 bl_dim_target
= bl_dim_fraction
= 0;
373 _backlight_off_normal();
376 #ifdef HAVE_LCD_SLEEP
377 backlight_lcd_sleep_countdown(true);
381 void backlight_set_fade_in(int value
)
384 bl_fade_in_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16) / value
;
389 void backlight_set_fade_out(int value
)
392 bl_fade_out_step
= ((BL_PWM_INTERVAL
*BL_PWM_COUNT
)<<16) / value
;
394 bl_fade_out_step
= 0;
396 #endif /* defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR) */
398 /* Update state of backlight according to timeout setting */
399 static void backlight_update_state(void)
401 #ifdef HAS_BUTTON_HOLD
402 if ((backlight_on_button_hold
!= 0)
403 #ifdef HAVE_REMOTE_LCD_AS_MAIN
404 && remote_button_hold()
409 backlight_timeout
= (backlight_on_button_hold
== 2) ? 0 : -1;
410 /* always on or always off */
414 if (charger_inserted()
415 #ifdef HAVE_USB_POWER
419 backlight_timeout
= backlight_timeout_plugged
;
422 backlight_timeout
= backlight_timeout_normal
;
424 /* Backlight == OFF in the setting? */
425 if (backlight_timeout
< 0)
427 backlight_timer
= 0; /* Disable the timeout */
432 backlight_timer
= backlight_timeout
;
437 #ifdef HAVE_REMOTE_LCD
438 /* Update state of remote backlight according to timeout setting */
439 static void remote_backlight_update_state(void)
441 #ifdef HAS_REMOTE_BUTTON_HOLD
442 if (remote_button_hold() && (remote_backlight_on_button_hold
!= 0))
443 remote_backlight_timeout
= (remote_backlight_on_button_hold
== 2)
444 ? 0 : -1; /* always on or always off */
448 if (charger_inserted()
449 #ifdef HAVE_USB_POWER
453 remote_backlight_timeout
= remote_backlight_timeout_plugged
;
456 remote_backlight_timeout
= remote_backlight_timeout_normal
;
458 /* Backlight == OFF in the setting? */
459 if (remote_backlight_timeout
< 0)
461 remote_backlight_timer
= 0; /* Disable the timeout */
462 _remote_backlight_off();
466 remote_backlight_timer
= remote_backlight_timeout
;
467 _remote_backlight_on();
470 #endif /* HAVE_REMOTE_LCD */
472 void backlight_thread(void)
474 struct queue_event ev
;
479 queue_wait(&backlight_queue
, &ev
);
481 { /* These events must always be processed */
482 #ifdef _BACKLIGHT_FADE_BOOST
483 case BACKLIGHT_FADE_FINISH
:
487 #ifdef _BACKLIGHT_FADE_ENABLE
488 case BACKLIGHT_FADE_FINISH
:
489 _backlight_hw_enable((bl_dim_current
|bl_dim_target
) != 0);
494 /* Here for now or else the aggressive init messes up scrolling */
495 #ifdef HAVE_REMOTE_LCD
496 case SYS_REMOTE_PLUGGED
:
501 case SYS_REMOTE_UNPLUGGED
:
504 #elif defined HAVE_REMOTE_LCD_AS_MAIN
505 case SYS_REMOTE_PLUGGED
:
510 case SYS_REMOTE_UNPLUGGED
:
513 #endif /* HAVE_REMOTE_LCD/ HAVE_REMOTE_LCD_AS_MAIN */
514 #endif /* !SIMULATOR */
516 /* This one here too for lack of a better place */
521 case SYS_USB_CONNECTED
:
522 /* Tell the USB thread that we are safe */
523 DEBUGF("backlight_thread got SYS_USB_CONNECTED\n");
524 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
527 case SYS_USB_DISCONNECTED
:
528 usb_acknowledge(SYS_USB_DISCONNECTED_ACK
);
531 #ifdef BACKLIGHT_DRIVER_CLOSE
532 /* Get out of here */
541 { /* These events are only processed if backlight isn't locked */
542 #ifdef HAVE_REMOTE_LCD
543 case REMOTE_BACKLIGHT_ON
:
544 remote_backlight_update_state();
547 case REMOTE_BACKLIGHT_OFF
:
548 remote_backlight_timer
= 0; /* Disable the timeout */
549 _remote_backlight_off();
551 #endif /* HAVE_REMOTE_LCD */
554 backlight_update_state();
558 backlight_timer
= 0; /* Disable the timeout */
562 #ifdef HAVE_LCD_SLEEP
567 #ifdef HAVE_BUTTON_LIGHT
568 case BUTTON_LIGHT_ON
:
569 buttonlight_update_state();
572 case BUTTON_LIGHT_OFF
:
573 buttonlight_timer
= 0;
578 case SYS_POWEROFF
: /* Lock backlight on poweroff so it doesn't */
579 locked
= true; /* go off before power is actually cut. */
582 case SYS_CHARGER_CONNECTED
:
583 case SYS_CHARGER_DISCONNECTED
:
585 backlight_update_state();
586 #ifdef HAVE_REMOTE_LCD
587 remote_backlight_update_state();
594 static void backlight_tick(void)
599 if(backlight_timer
== 0)
604 #ifdef HAVE_LCD_SLEEP
605 else if(lcd_sleep_timer
)
608 if(lcd_sleep_timer
== 0)
610 /* Queue on bl thread or freeze! */
611 queue_post(&backlight_queue
, LCD_SLEEP
, 0);
614 #endif /* HAVE_LCD_SLEEP */
616 #ifdef HAVE_REMOTE_LCD
617 if(remote_backlight_timer
)
619 remote_backlight_timer
--;
620 if(remote_backlight_timer
== 0)
622 remote_backlight_off();
625 #endif /* HAVE_REMOVE_LCD */
626 #ifdef HAVE_BUTTON_LIGHT
627 if (buttonlight_timer
)
630 if (buttonlight_timer
== 0)
635 #endif /* HAVE_BUTTON_LIGHT */
638 void backlight_init(void)
640 queue_init(&backlight_queue
, true);
643 if (_backlight_init())
645 # ifdef HAVE_BACKLIGHT_PWM_FADING
646 /* If backlight is already on, don't fade in. */
647 bl_dim_target
= BL_PWM_COUNT
;
648 bl_dim_fraction
= (BL_PWM_COUNT
<<16);
652 /* Leave all lights as set by the bootloader here. The settings load will
653 * call the appropriate backlight_set_*() functions, only changing light
654 * status if necessary. */
655 #ifdef BACKLIGHT_DRIVER_CLOSE
658 create_thread(backlight_thread
, backlight_stack
,
659 sizeof(backlight_stack
), 0, backlight_thread_name
660 IF_PRIO(, PRIORITY_USER_INTERFACE
)
662 tick_add_task(backlight_tick
);
665 #ifdef BACKLIGHT_DRIVER_CLOSE
666 void backlight_close(void)
668 struct thread_entry
*thread
= backlight_thread_p
;
670 /* Wait for thread to exit */
674 backlight_thread_p
= NULL
;
676 queue_post(&backlight_queue
, BACKLIGHT_QUIT
, 0);
679 #endif /* BACKLIGHT_DRIVER_CLOSE */
681 void backlight_on(void)
683 queue_remove_from_head(&backlight_queue
, BACKLIGHT_ON
);
684 queue_post(&backlight_queue
, BACKLIGHT_ON
, 0);
687 void backlight_off(void)
689 queue_post(&backlight_queue
, BACKLIGHT_OFF
, 0);
692 /* returns true when the backlight is on,
693 * and optionally when it's set to always off. */
694 bool is_backlight_on(bool ignore_always_off
)
696 return (backlight_timer
> 0) /* countdown */
697 || (backlight_timeout
== 0) /* always on */
698 || ((backlight_timeout
< 0) && !ignore_always_off
);
701 /* return value in ticks; 0 means always on, <0 means always off */
702 int backlight_get_current_timeout(void)
704 return backlight_timeout
;
707 void backlight_set_timeout(int value
)
709 backlight_timeout_normal
= HZ
* value
;
710 backlight_update_state();
714 void backlight_set_timeout_plugged(int value
)
716 backlight_timeout_plugged
= HZ
* value
;
717 backlight_update_state();
719 #endif /* CONFIG_CHARGING */
721 #ifdef HAS_BUTTON_HOLD
722 /* Hold button change event handler. */
723 void backlight_hold_changed(bool hold_button
)
725 if (!hold_button
|| (backlight_on_button_hold
> 0))
726 /* if unlocked or override in effect */
730 void backlight_set_on_button_hold(int index
)
732 if ((unsigned)index
>= 3)
733 /* if given a weird value, use default */
736 backlight_on_button_hold
= index
;
737 backlight_update_state();
739 #endif /* HAS_BUTTON_HOLD */
741 #ifdef HAVE_LCD_SLEEP_SETTING
742 void lcd_set_sleep_after_backlight_off(int index
)
744 if ((unsigned)index
>= sizeof(lcd_sleep_timeout_value
))
745 /* if given a weird value, use default */
748 lcd_sleep_timeout
= HZ
* lcd_sleep_timeout_value
[index
];
750 if (backlight_timer
> 0 || backlight_get_current_timeout() == 0)
751 /* Timer will be set when bl turns off or bl set to on. */
754 /* Backlight is Off */
755 if (lcd_sleep_timeout
< 0)
756 lcd_sleep_timer
= 1; /* Always - sleep next tick */
758 lcd_sleep_timer
= lcd_sleep_timeout
; /* Never, other */
760 #endif /* HAVE_LCD_SLEEP_SETTING */
762 #ifdef HAVE_REMOTE_LCD
763 void remote_backlight_on(void)
765 queue_post(&backlight_queue
, REMOTE_BACKLIGHT_ON
, 0);
768 void remote_backlight_off(void)
770 queue_post(&backlight_queue
, REMOTE_BACKLIGHT_OFF
, 0);
773 void remote_backlight_set_timeout(int value
)
775 remote_backlight_timeout_normal
= HZ
* value
;
776 remote_backlight_update_state();
780 void remote_backlight_set_timeout_plugged(int value
)
782 remote_backlight_timeout_plugged
= HZ
* value
;
783 remote_backlight_update_state();
785 #endif /* CONFIG_CHARGING */
787 #ifdef HAS_REMOTE_BUTTON_HOLD
788 /* Remote hold button change event handler. */
789 void remote_backlight_hold_changed(bool rc_hold_button
)
791 if (!rc_hold_button
|| (remote_backlight_on_button_hold
> 0))
792 /* if unlocked or override */
793 remote_backlight_on();
796 void remote_backlight_set_on_button_hold(int index
)
798 if ((unsigned)index
>= 3)
799 /* if given a weird value, use default */
802 remote_backlight_on_button_hold
= index
;
803 remote_backlight_update_state();
805 #endif /* HAS_REMOTE_BUTTON_HOLD */
807 /* return value in ticks; 0 means always on, <0 means always off */
808 int remote_backlight_get_current_timeout(void)
810 return remote_backlight_timeout
;
813 /* returns true when the backlight is on, and
814 * optionally when it's set to always off */
815 bool is_remote_backlight_on(bool ignore_always_off
)
817 return (remote_backlight_timer
> 0) /* countdown */
818 || (remote_backlight_timeout
== 0) /* always on */
819 || ((remote_backlight_timeout
< 0) && !ignore_always_off
);
822 #endif /* HAVE_REMOTE_LCD */
824 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
825 void backlight_set_brightness(int val
)
827 if (val
< MIN_BRIGHTNESS_SETTING
)
828 val
= MIN_BRIGHTNESS_SETTING
;
829 else if (val
> MAX_BRIGHTNESS_SETTING
)
830 val
= MAX_BRIGHTNESS_SETTING
;
832 _backlight_set_brightness(val
);
834 #endif /* HAVE_BACKLIGHT_BRIGHTNESS */
836 #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
837 void buttonlight_set_brightness(int val
)
839 if (val
< MIN_BRIGHTNESS_SETTING
)
840 val
= MIN_BRIGHTNESS_SETTING
;
841 else if (val
> MAX_BRIGHTNESS_SETTING
)
842 val
= MAX_BRIGHTNESS_SETTING
;
844 _buttonlight_set_brightness(val
);
846 #endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */
848 #else /* !defined(HAVE_BACKLIGHT) || !defined(BACKLIGHT_FULL_INIT)
849 -- no backlight, empty dummy functions */
851 #if defined(HAVE_BACKLIGHT) && !defined(BACKLIGHT_FULL_INIT)
852 void backlight_init(void)
854 (void)_backlight_init();
859 void backlight_on(void) {}
860 void backlight_off(void) {}
861 void buttonlight_on(void) {}
862 void backlight_set_timeout(int value
) {(void)value
;}
864 bool is_backlight_on(bool ignore_always_off
)
866 (void)ignore_always_off
;
869 #ifdef HAVE_REMOTE_LCD
870 void remote_backlight_on(void) {}
871 void remote_backlight_off(void) {}
872 void remote_backlight_set_timeout(int value
) {(void)value
;}
874 bool is_remote_backlight_on(bool ignore_always_off
)
876 (void)ignore_always_off
;
879 #endif /* HAVE_REMOTE_LCD */
880 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
881 void backlight_set_brightness(int val
) { (void)val
; }
883 #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
884 void buttonlight_set_brightness(int val
) { (void)val
; }
886 #endif /* defined(HAVE_BACKLIGHT) && defined(BACKLIGHT_FULL_INIT) */