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)
92 const signed char backlight_timeout_value
[19] =
94 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 45, 60, 90
100 #ifdef HAVE_REMOTE_LCD
102 REMOTE_BACKLIGHT_OFF
,
104 #if defined(_BACKLIGHT_FADE_BOOST) || defined(_BACKLIGHT_FADE_ENABLE)
105 BACKLIGHT_FADE_FINISH
,
107 #ifdef HAVE_LCD_SLEEP
110 #ifdef HAVE_BUTTON_LIGHT
116 static void backlight_thread(void);
117 static long backlight_stack
[DEFAULT_STACK_SIZE
/sizeof(long)];
118 static const char backlight_thread_name
[] = "backlight";
119 static struct event_queue backlight_queue
;
121 static int backlight_timer
;
122 static int backlight_timeout
;
123 static int backlight_timeout_normal
= 5*HZ
;
125 static int backlight_timeout_plugged
= 5*HZ
;
127 #ifdef HAS_BUTTON_HOLD
128 static int backlight_on_button_hold
= 0;
131 #ifdef HAVE_BUTTON_LIGHT
132 static int buttonlight_timer
;
133 int _buttonlight_timeout
= 5*HZ
;
135 /* Update state of buttonlight according to timeout setting */
136 static void buttonlight_update_state(void)
138 buttonlight_timer
= _buttonlight_timeout
;
140 /* Buttonlight == OFF in the setting? */
141 if (buttonlight_timer
< 0)
143 buttonlight_timer
= 0; /* Disable the timeout */
150 /* external interface */
151 void buttonlight_on(void)
153 queue_remove_from_head(&backlight_queue
, BUTTON_LIGHT_ON
);
154 queue_post(&backlight_queue
, BUTTON_LIGHT_ON
, 0);
157 void buttonlight_off(void)
159 queue_post(&backlight_queue
, BUTTON_LIGHT_OFF
, 0);
162 void buttonlight_set_timeout(int index
)
164 if((unsigned)index
>= sizeof(backlight_timeout_value
))
165 /* if given a weird value, use default */
167 _buttonlight_timeout
= HZ
* backlight_timeout_value
[index
];
168 buttonlight_update_state();
173 #ifdef HAVE_REMOTE_LCD
174 static int remote_backlight_timer
;
175 static int remote_backlight_timeout
;
176 static int remote_backlight_timeout_normal
= 5*HZ
;
178 static int remote_backlight_timeout_plugged
= 5*HZ
;
180 #ifdef HAS_REMOTE_BUTTON_HOLD
181 static int remote_backlight_on_button_hold
= 0;
185 #ifdef HAVE_LCD_SLEEP
186 const signed char lcd_sleep_timeout_value
[10] =
188 -1, 0, 5, 10, 15, 20, 30, 45, 60, 90
190 int _lcd_sleep_timer
;
191 int _lcd_sleep_timeout
= 10*HZ
;
194 #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
195 /* backlight fading */
196 #define BL_PWM_INTERVAL 5000 /* Cycle interval in us */
197 #define BL_PWM_COUNT 100
198 static const char backlight_fade_value
[8] = { 0, 1, 2, 4, 6, 8, 10, 20 };
199 static int fade_in_count
= 1;
200 static int fade_out_count
= 4;
202 static bool bl_timer_active
= false;
203 static int bl_dim_current
= 0;
204 static int bl_dim_target
= 0;
205 static int bl_pwm_counter
= 0;
206 static volatile int bl_cycle_counter
= 0;
207 static enum {DIM_STATE_START
, DIM_STATE_MAIN
} bl_dim_state
= DIM_STATE_START
;
209 static void backlight_isr(void)
214 timer_period
= TIMER_FREQ
/ 1000 * BL_PWM_INTERVAL
/ 1000;
215 switch (bl_dim_state
)
218 case DIM_STATE_START
:
222 if (bl_dim_current
> 0 && bl_dim_current
< BL_PWM_COUNT
)
225 bl_pwm_counter
= bl_dim_current
;
226 timer_period
= timer_period
* bl_pwm_counter
/ BL_PWM_COUNT
;
227 bl_dim_state
= DIM_STATE_MAIN
;
234 _backlight_off_isr();
235 if (bl_dim_current
== bl_dim_target
)
241 /* Dim main screen */
243 _backlight_off_isr();
244 bl_dim_state
= DIM_STATE_START
;
245 timer_period
= timer_period
* (BL_PWM_COUNT
- bl_pwm_counter
) / BL_PWM_COUNT
;
249 if ((bl_dim_target
> bl_dim_current
) && (bl_cycle_counter
>= fade_in_count
))
252 bl_cycle_counter
= 0;
255 if ((bl_dim_target
< bl_dim_current
) && (bl_cycle_counter
>= fade_out_count
))
258 bl_cycle_counter
= 0;
263 #if defined(_BACKLIGHT_FADE_BOOST) || defined(_BACKLIGHT_FADE_ENABLE)
264 queue_post(&backlight_queue
, BACKLIGHT_FADE_FINISH
, 0);
267 bl_timer_active
= false;
270 timer_set_period(timer_period
);
273 static void backlight_switch(void)
275 if (bl_dim_target
> (BL_PWM_COUNT
/2))
277 _backlight_on_normal();
278 bl_dim_current
= BL_PWM_COUNT
;
282 _backlight_off_normal();
287 static void backlight_release_timer(void)
289 #ifdef _BACKLIGHT_FADE_BOOST
293 bl_timer_active
= false;
297 static void backlight_dim(int value
)
299 /* protect from extraneous calls with the same target value */
300 if (value
== bl_dim_target
)
303 bl_dim_target
= value
;
308 if (timer_register(0, backlight_release_timer
, 2, 0, backlight_isr
))
310 #ifdef _BACKLIGHT_FADE_BOOST
311 /* Prevent cpu frequency changes while dimming. */
314 bl_timer_active
= true;
320 static void _backlight_on(void)
322 if (fade_in_count
> 0)
324 #ifdef _BACKLIGHT_FADE_ENABLE
325 _backlight_hw_enable(true);
327 backlight_dim(BL_PWM_COUNT
);
331 bl_dim_target
= bl_dim_current
= BL_PWM_COUNT
;
332 _backlight_on_normal();
334 #ifdef HAVE_LCD_SLEEP
335 _lcd_sleep_timer
= 0; /* LCD should be awake already */
339 static void _backlight_off(void)
341 if (fade_out_count
> 0)
347 bl_dim_target
= bl_dim_current
= 0;
348 _backlight_off_normal();
350 #ifdef HAVE_LCD_SLEEP
351 /* Start LCD sleep countdown */
352 if (_lcd_sleep_timeout
< 0)
354 _lcd_sleep_timer
= 0; /* Setting == Always */
358 _lcd_sleep_timer
= _lcd_sleep_timeout
;
362 void backlight_set_fade_in(int index
)
364 fade_in_count
= backlight_fade_value
[index
];
367 void backlight_set_fade_out(int index
)
369 fade_out_count
= backlight_fade_value
[index
];
371 #endif /* defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR) */
373 /* Update state of backlight according to timeout setting */
374 static void backlight_update_state(void)
376 #ifdef HAS_BUTTON_HOLD
377 if (button_hold() && (backlight_on_button_hold
!= 0))
378 backlight_timeout
= (backlight_on_button_hold
== 2) ? 0 : -1;
379 /* always on or always off */
383 if (charger_inserted()
384 #ifdef HAVE_USB_POWER
388 backlight_timeout
= backlight_timeout_plugged
;
391 backlight_timeout
= backlight_timeout_normal
;
393 /* Backlight == OFF in the setting? */
394 if (backlight_timeout
< 0)
396 backlight_timer
= 0; /* Disable the timeout */
401 backlight_timer
= backlight_timeout
;
406 #ifdef HAVE_REMOTE_LCD
407 /* Update state of remote backlight according to timeout setting */
408 static void remote_backlight_update_state(void)
410 #ifdef HAS_REMOTE_BUTTON_HOLD
411 if (remote_button_hold() && (remote_backlight_on_button_hold
!= 0))
412 remote_backlight_timeout
= (remote_backlight_on_button_hold
== 2)
413 ? 0 : -1; /* always on or always off */
417 if (charger_inserted()
418 #ifdef HAVE_USB_POWER
422 remote_backlight_timeout
= remote_backlight_timeout_plugged
;
425 remote_backlight_timeout
= remote_backlight_timeout_normal
;
427 /* Backlight == OFF in the setting? */
428 if (remote_backlight_timeout
< 0)
430 remote_backlight_timer
= 0; /* Disable the timeout */
431 _remote_backlight_off();
435 remote_backlight_timer
= remote_backlight_timeout
;
436 _remote_backlight_on();
439 #endif /* HAVE_REMOTE_LCD */
441 void backlight_thread(void)
443 struct queue_event ev
;
448 queue_wait(&backlight_queue
, &ev
);
450 { /* These events must always be processed */
451 #ifdef _BACKLIGHT_FADE_BOOST
452 case BACKLIGHT_FADE_FINISH
:
456 #ifdef _BACKLIGHT_FADE_ENABLE
457 case BACKLIGHT_FADE_FINISH
:
458 _backlight_hw_enable((bl_dim_current
|bl_dim_target
) != 0);
462 #if defined(HAVE_REMOTE_LCD) && !defined(SIMULATOR)
463 /* Here for now or else the aggressive init messes up scrolling */
464 case SYS_REMOTE_PLUGGED
:
469 case SYS_REMOTE_UNPLUGGED
:
472 #endif /* defined(HAVE_REMOTE_LCD) && !defined(SIMULATOR) */
474 /* This one here too for lack of a better place */
479 case SYS_USB_CONNECTED
:
480 /* Tell the USB thread that we are safe */
481 DEBUGF("backlight_thread got SYS_USB_CONNECTED\n");
482 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
485 case SYS_USB_DISCONNECTED
:
486 usb_acknowledge(SYS_USB_DISCONNECTED_ACK
);
493 { /* These events are only processed if backlight isn't locked */
494 #ifdef HAVE_REMOTE_LCD
495 case REMOTE_BACKLIGHT_ON
:
496 remote_backlight_update_state();
499 case REMOTE_BACKLIGHT_OFF
:
500 remote_backlight_timer
= 0; /* Disable the timeout */
501 _remote_backlight_off();
503 #endif /* HAVE_REMOTE_LCD */
506 backlight_update_state();
510 backlight_timer
= 0; /* Disable the timeout */
514 #ifdef HAVE_LCD_SLEEP
519 #ifdef HAVE_BUTTON_LIGHT
520 case BUTTON_LIGHT_ON
:
521 buttonlight_update_state();
524 case BUTTON_LIGHT_OFF
:
525 buttonlight_timer
= 0;
530 case SYS_POWEROFF
: /* Lock backlight on poweroff so it doesn't */
531 locked
= true; /* go off before power is actually cut. */
534 case SYS_CHARGER_CONNECTED
:
535 case SYS_CHARGER_DISCONNECTED
:
537 backlight_update_state();
538 #ifdef HAVE_REMOTE_LCD
539 remote_backlight_update_state();
546 static void backlight_tick(void)
551 if(backlight_timer
== 0)
556 #ifdef HAVE_LCD_SLEEP
557 else if(_lcd_sleep_timer
)
560 if(_lcd_sleep_timer
== 0)
562 /* Queue on bl thread or freeze! */
563 queue_post(&backlight_queue
, LCD_SLEEP
, 0);
566 #endif /* HAVE_LCD_SLEEP */
568 #ifdef HAVE_REMOTE_LCD
569 if(remote_backlight_timer
)
571 remote_backlight_timer
--;
572 if(remote_backlight_timer
== 0)
574 remote_backlight_off();
577 #endif /* HAVE_REMOVE_LCD */
578 #ifdef HAVE_BUTTON_LIGHT
579 if (buttonlight_timer
)
582 if (buttonlight_timer
== 0)
587 #endif /* HAVE_BUTTON_LIGHT */
590 void backlight_init(void)
592 queue_init(&backlight_queue
, true);
595 if (_backlight_init())
597 # ifdef HAVE_BACKLIGHT_PWM_FADING
598 /* If backlight is already on, don't fade in. */
599 bl_dim_current
= BL_PWM_COUNT
;
600 bl_dim_target
= BL_PWM_COUNT
;
604 /* Leave all lights as set by the bootloader here. The settings load will
605 * call the appropriate backlight_set_*() functions, only changing light
606 * status if necessary. */
608 create_thread(backlight_thread
, backlight_stack
,
609 sizeof(backlight_stack
), 0, backlight_thread_name
610 IF_PRIO(, PRIORITY_SYSTEM
)
612 tick_add_task(backlight_tick
);
615 void backlight_on(void)
617 queue_remove_from_head(&backlight_queue
, BACKLIGHT_ON
);
618 queue_post(&backlight_queue
, BACKLIGHT_ON
, 0);
621 void backlight_off(void)
623 queue_post(&backlight_queue
, BACKLIGHT_OFF
, 0);
626 /* returns true when the backlight is on OR when it's set to always off */
627 bool is_backlight_on(void)
629 if (backlight_timer
|| backlight_timeout
<= 0)
635 /* return value in ticks; 0 means always on, <0 means always off */
636 int backlight_get_current_timeout(void)
638 return backlight_timeout
;
641 void backlight_set_timeout(int index
)
643 if((unsigned)index
>= sizeof(backlight_timeout_value
))
644 /* if given a weird value, use default */
646 backlight_timeout_normal
= HZ
* backlight_timeout_value
[index
];
647 backlight_update_state();
651 void backlight_set_timeout_plugged(int index
)
653 if((unsigned)index
>= sizeof(backlight_timeout_value
))
654 /* if given a weird value, use default */
656 backlight_timeout_plugged
= HZ
* backlight_timeout_value
[index
];
657 backlight_update_state();
659 #endif /* CONFIG_CHARGING */
661 #ifdef HAS_BUTTON_HOLD
662 /* Hold button change event handler. */
663 void backlight_hold_changed(bool hold_button
)
665 if (!hold_button
|| (backlight_on_button_hold
> 0))
666 /* if unlocked or override in effect */
670 void backlight_set_on_button_hold(int index
)
672 if ((unsigned)index
>= 3)
673 /* if given a weird value, use default */
676 backlight_on_button_hold
= index
;
677 backlight_update_state();
679 #endif /* HAS_BUTTON_HOLD */
681 #ifdef HAVE_LCD_SLEEP
682 void lcd_set_sleep_after_backlight_off(int index
)
684 if ((unsigned)index
>= sizeof(lcd_sleep_timeout_value
))
685 /* if given a weird value, use default */
688 _lcd_sleep_timeout
= HZ
* lcd_sleep_timeout_value
[index
];
690 if (backlight_timer
> 0 || backlight_get_current_timeout() == 0)
691 /* Timer will be set when bl turns off or bl set to on. */
694 /* Backlight is Off */
695 if (_lcd_sleep_timeout
< 0)
696 _lcd_sleep_timer
= 1; /* Always - sleep next tick */
698 _lcd_sleep_timer
= _lcd_sleep_timeout
; /* Never, other */
700 #endif /* HAVE_LCD_SLEEP */
702 #ifdef HAVE_REMOTE_LCD
703 void remote_backlight_on(void)
705 queue_post(&backlight_queue
, REMOTE_BACKLIGHT_ON
, 0);
708 void remote_backlight_off(void)
710 queue_post(&backlight_queue
, REMOTE_BACKLIGHT_OFF
, 0);
713 void remote_backlight_set_timeout(int index
)
715 if((unsigned)index
>= sizeof(backlight_timeout_value
))
716 /* if given a weird value, use default */
718 remote_backlight_timeout_normal
= HZ
* backlight_timeout_value
[index
];
719 remote_backlight_update_state();
723 void remote_backlight_set_timeout_plugged(int index
)
725 if((unsigned)index
>= sizeof(backlight_timeout_value
))
726 /* if given a weird value, use default */
728 remote_backlight_timeout_plugged
= HZ
* backlight_timeout_value
[index
];
729 remote_backlight_update_state();
731 #endif /* CONFIG_CHARGING */
733 #ifdef HAS_REMOTE_BUTTON_HOLD
734 /* Remote hold button change event handler. */
735 void remote_backlight_hold_changed(bool rc_hold_button
)
737 if (!rc_hold_button
|| (remote_backlight_on_button_hold
> 0))
738 /* if unlocked or override */
739 remote_backlight_on();
742 void remote_backlight_set_on_button_hold(int index
)
744 if ((unsigned)index
>= 3)
745 /* if given a weird value, use default */
748 remote_backlight_on_button_hold
= index
;
749 remote_backlight_update_state();
751 #endif /* HAS_REMOTE_BUTTON_HOLD */
753 /* return value in ticks; 0 means always on, <0 means always off */
754 int remote_backlight_get_current_timeout(void)
756 return remote_backlight_timeout
;
759 /* returns true when the backlight is on OR when it's set to always off */
760 bool is_remote_backlight_on(void)
762 if (remote_backlight_timer
!= 0 || remote_backlight_timeout
<= 0)
768 #endif /* HAVE_REMOTE_LCD */
770 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
771 void backlight_set_brightness(int val
)
773 if (val
< MIN_BRIGHTNESS_SETTING
)
774 val
= MIN_BRIGHTNESS_SETTING
;
775 else if (val
> MAX_BRIGHTNESS_SETTING
)
776 val
= MAX_BRIGHTNESS_SETTING
;
778 _backlight_set_brightness(val
);
780 #endif /* HAVE_BACKLIGHT_BRIGHTNESS */
782 #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
783 void buttonlight_set_brightness(int val
)
785 if (val
< MIN_BRIGHTNESS_SETTING
)
786 val
= MIN_BRIGHTNESS_SETTING
;
787 else if (val
> MAX_BRIGHTNESS_SETTING
)
788 val
= MAX_BRIGHTNESS_SETTING
;
790 _buttonlight_set_brightness(val
);
792 #endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */
794 #else /* !defined(HAVE_BACKLIGHT) || defined(BOOTLOADER)
795 -- no backlight, empty dummy functions */
797 #if defined(BOOTLOADER) && defined(HAVE_BACKLIGHT)
798 void backlight_init(void)
800 (void)_backlight_init();
805 void backlight_on(void) {}
806 void backlight_off(void) {}
807 void buttonlight_on(void) {}
808 void backlight_set_timeout(int index
) {(void)index
;}
809 bool is_backlight_on(void) {return true;}
810 #ifdef HAVE_REMOTE_LCD
811 void remote_backlight_on(void) {}
812 void remote_backlight_off(void) {}
813 void remote_backlight_set_timeout(int index
) {(void)index
;}
814 bool is_remote_backlight_on(void) {return true;}
815 #endif /* HAVE_REMOTE_LCD */
816 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
817 void backlight_set_brightness(int val
) { (void)val
; }
819 #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
820 void buttonlight_set_brightness(int val
) { (void)val
; }
822 #endif /* defined(HAVE_BACKLIGHT) && !defined(BOOTLOADER) */