Work-in-progress iriver iFP-7xx port by Tomasz Malesinski
[Rockbox.git] / firmware / backlight.c
blobb475c61fc052734b0fe60ab5732317228a0c68e7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
19 #include "config.h"
20 #include <stdlib.h>
21 #include "cpu.h"
22 #include "kernel.h"
23 #include "thread.h"
24 #include "i2c.h"
25 #include "debug.h"
26 #include "rtc.h"
27 #include "usb.h"
28 #include "power.h"
29 #include "system.h"
30 #include "timer.h"
31 #include "backlight.h"
33 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
34 #include "pcf50606.h" /* iRiver brightness */
35 #endif
37 #if CONFIG_BACKLIGHT == BL_IRIVER_H300
38 #include "lcd.h" /* for lcd_enable() */
39 #endif
40 #ifdef HAVE_REMOTE_LCD
41 #include "lcd-remote.h"
42 #endif
44 #if defined(CONFIG_BACKLIGHT) && !defined(BOOTLOADER)
46 const char backlight_timeout_value[19] =
48 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 45, 60, 90
51 #define BACKLIGHT_ON 1
52 #define BACKLIGHT_OFF 2
53 #define REMOTE_BACKLIGHT_ON 3
54 #define REMOTE_BACKLIGHT_OFF 4
55 #define BACKLIGHT_UNBOOST_CPU 5
57 static void backlight_thread(void);
58 static long backlight_stack[DEFAULT_STACK_SIZE/sizeof(long)];
59 static const char backlight_thread_name[] = "backlight";
60 static struct event_queue backlight_queue;
62 static int backlight_timer;
63 static int backlight_timeout = 5*HZ;
64 #ifdef HAVE_CHARGING
65 static int backlight_timeout_plugged = 5*HZ;
66 #endif
68 #ifdef HAVE_REMOTE_LCD
69 static int remote_backlight_timer;
70 static int remote_backlight_timeout = 5*HZ;
71 #ifdef HAVE_CHARGING
72 static int remote_backlight_timeout_plugged = 5*HZ;
73 #endif
74 #endif
76 #if (CONFIG_BACKLIGHT == BL_IRIVER_H100) && !defined(SIMULATOR)
77 /* backlight fading */
78 #define BL_PWM_INTERVAL 5000 /* Cycle interval in µs */
79 #define BL_PWM_COUNT 100
80 static const char backlight_fade_value[8] = { 0, 1, 2, 4, 6, 8, 10, 20 };
81 static int fade_in_count = 1;
82 static int fade_out_count = 4;
84 static bool bl_timer_active = false;
85 static int bl_dim_current = BL_PWM_COUNT;
86 static int bl_dim_target = BL_PWM_COUNT;
87 static int bl_pwm_counter = 0;
88 static volatile int bl_cycle_counter = 0;
89 static enum {DIM_STATE_START, DIM_STATE_MAIN} bl_dim_state = DIM_STATE_START;
91 static void backlight_isr(void)
93 int timer_period;
94 bool idle = false;
96 timer_period = CPU_FREQ / 1000 * BL_PWM_INTERVAL / 1000;
97 switch (bl_dim_state)
99 /* New cycle */
100 case DIM_STATE_START:
101 bl_pwm_counter = 0;
102 bl_cycle_counter++;
104 if (bl_dim_current > 0 && bl_dim_current < BL_PWM_COUNT)
106 and_l(~0x00020000, &GPIO1_OUT);
107 bl_pwm_counter = bl_dim_current;
108 timer_period = timer_period * bl_pwm_counter / BL_PWM_COUNT;
109 bl_dim_state = DIM_STATE_MAIN;
111 else
113 if (bl_dim_current)
114 and_l(~0x00020000, &GPIO1_OUT);
115 else
116 or_l(0x00020000, &GPIO1_OUT);
118 if (bl_dim_current == bl_dim_target)
119 idle = true;
122 break ;
124 /* Dim main screen */
125 case DIM_STATE_MAIN:
126 or_l(0x00020000, &GPIO1_OUT);
127 bl_dim_state = DIM_STATE_START;
128 timer_period = timer_period * (BL_PWM_COUNT - bl_pwm_counter) / BL_PWM_COUNT;
129 break ;
132 if ((bl_dim_target > bl_dim_current) && (bl_cycle_counter >= fade_in_count))
134 bl_dim_current++;
135 bl_cycle_counter = 0;
138 if ((bl_dim_target < bl_dim_current) && (bl_cycle_counter >= fade_out_count))
140 bl_dim_current--;
141 bl_cycle_counter = 0;
144 if (idle)
146 queue_post(&backlight_queue, BACKLIGHT_UNBOOST_CPU, NULL);
147 timer_unregister();
148 bl_timer_active = false;
150 else
151 timer_set_period(timer_period);
154 static void backlight_switch(void)
156 if (bl_dim_target > (BL_PWM_COUNT/2))
158 and_l(~0x00020000, &GPIO1_OUT);
159 bl_dim_current = BL_PWM_COUNT;
161 else
163 or_l(0x00020000, &GPIO1_OUT);
164 bl_dim_current = 0;
168 static void backlight_release_timer(void)
170 cpu_boost(false);
171 timer_unregister();
172 bl_timer_active = false;
173 backlight_switch();
176 static void backlight_dim(int value)
178 /* protect from extraneous calls with the same target value */
179 if (value == bl_dim_target)
180 return;
182 bl_dim_target = value;
184 if (bl_timer_active)
185 return ;
187 if (timer_register(0, backlight_release_timer, 1, 0, backlight_isr))
189 /* Prevent cpu frequency changes while dimming. */
190 cpu_boost(true);
191 bl_timer_active = true;
193 else
194 backlight_switch();
197 void backlight_set_fade_in(int index)
199 fade_in_count = backlight_fade_value[index];
202 void backlight_set_fade_out(int index)
204 fade_out_count = backlight_fade_value[index];
206 #endif /* (CONFIG_BACKLIGHT == BL_IRIVER_H100) && !defined(SIMULATOR) */
208 static void __backlight_on(void)
210 #ifdef SIMULATOR
211 sim_backlight(100);
212 #elif CONFIG_BACKLIGHT == BL_IRIVER_H100
213 if (fade_in_count > 0)
214 backlight_dim(BL_PWM_COUNT);
215 else
217 bl_dim_target = bl_dim_current = BL_PWM_COUNT;
218 and_l(~0x00020000, &GPIO1_OUT);
220 #elif CONFIG_BACKLIGHT == BL_IRIVER_H300
221 lcd_enable(true);
222 or_l(0x00020000, &GPIO1_OUT);
223 #elif CONFIG_BACKLIGHT == BL_RTC
224 /* Enable square wave */
225 rtc_write(0x0a, rtc_read(0x0a) | 0x40);
226 #elif CONFIG_BACKLIGHT == BL_PA14_LO /* Player */
227 and_b(~0x40, &PADRH); /* drive and set low */
228 or_b(0x40, &PAIORH);
229 #elif CONFIG_BACKLIGHT == BL_PA14_HI /* Ondio */
230 or_b(0x40, &PADRH); /* drive it high */
231 #elif CONFIG_BACKLIGHT == BL_GMINI
232 P1 |= 0x10;
233 #elif CONFIG_BACKLIGHT == BL_IPOD4G
234 /* brightness full */
235 outl(0x80000000 | (0xff << 16), 0x7000a010);
237 /* set port b bit 3 on */
238 outl(((0x100 | 1) << 3), 0x6000d824);
239 #elif CONFIG_BACKLIGHT==BL_IPODNANO
240 /* set port B03 on */
241 outl(((0x100 | 1) << 3), 0x6000d824);
243 /* set port L07 on */
244 outl(((0x100 | 1) << 7), 0x6000d12c);
245 #elif CONFIG_BACKLIGHT==BL_IRIVER_IFP7XX
246 GPIO3_SET = 1;
247 #endif
250 static void __backlight_off(void)
252 #ifdef SIMULATOR
253 sim_backlight(0);
254 #elif CONFIG_BACKLIGHT == BL_IRIVER_H100
255 if (fade_out_count > 0)
256 backlight_dim(0);
257 else
259 bl_dim_target = bl_dim_current = 0;
260 or_l(0x00020000, &GPIO1_OUT);
262 #elif CONFIG_BACKLIGHT == BL_IRIVER_H300
263 and_l(~0x00020000, &GPIO1_OUT);
264 lcd_enable(false);
265 #elif CONFIG_BACKLIGHT == BL_RTC
266 /* Disable square wave */
267 rtc_write(0x0a, rtc_read(0x0a) & ~0x40);
268 #elif CONFIG_BACKLIGHT == BL_PA14_LO /* Player */
269 and_b(~0x40, &PAIORH); /* let it float (up) */
270 #elif CONFIG_BACKLIGHT == BL_PA14_HI /* Ondio */
271 and_b(~0x40, &PADRH); /* drive it low */
272 #elif CONFIG_BACKLIGHT == BL_GMINI
273 P1 &= ~0x10;
274 #elif CONFIG_BACKLIGHT == BL_IPOD4G
275 /* fades backlight off on 4g */
276 outl(inl(0x70000084) & ~0x2000000, 0x70000084);
277 outl(0x80000000, 0x7000a010);
278 #elif CONFIG_BACKLIGHT==BL_IPODNANO
279 /* set port B03 off */
280 outl(((0x100 | 0) << 3), 0x6000d824);
282 /* set port L07 off */
283 outl(((0x100 | 0) << 7), 0x6000d12c);
284 #elif CONFIG_BACKLIGHT==BL_IRIVER_IFP7XX
285 GPIO3_CLR = 1;
286 #endif
289 #ifdef HAVE_REMOTE_LCD
290 static void __remote_backlight_on(void)
292 #ifdef SIMULATOR
293 sim_remote_backlight(100);
294 #elif defined(IRIVER_H300_SERIES)
295 and_l(~0x00000002, &GPIO1_OUT);
296 #else
297 and_l(~0x00000800, &GPIO_OUT);
298 #endif
301 static void __remote_backlight_off(void)
303 #ifdef SIMULATOR
304 sim_remote_backlight(0);
305 #elif defined(IRIVER_H300_SERIES)
306 or_l(0x00000002, &GPIO1_OUT);
307 #else
308 or_l(0x00000800, &GPIO_OUT);
309 #endif
311 #endif /* HAVE_REMOTE_LCD */
313 void backlight_thread(void)
315 struct event ev;
317 while(1)
319 queue_wait(&backlight_queue, &ev);
320 switch(ev.id)
322 #ifdef HAVE_REMOTE_LCD
323 case REMOTE_BACKLIGHT_ON:
324 #ifdef HAVE_CHARGING
325 if (charger_inserted())
326 remote_backlight_timer = remote_backlight_timeout_plugged;
327 else
328 #endif
329 remote_backlight_timer = remote_backlight_timeout;
331 /* Backlight == OFF in the setting? */
332 if (remote_backlight_timer < 0)
334 remote_backlight_timer = 0; /* Disable the timeout */
335 __remote_backlight_off();
337 else
339 __remote_backlight_on();
341 break;
343 case REMOTE_BACKLIGHT_OFF:
344 __remote_backlight_off();
345 break;
347 #endif /* HAVE_REMOTE_LCD */
348 case BACKLIGHT_ON:
349 #ifdef HAVE_CHARGING
350 if (charger_inserted())
351 backlight_timer = backlight_timeout_plugged;
352 else
353 #endif
354 backlight_timer = backlight_timeout;
356 if (backlight_timer < 0) /* Backlight == OFF in the setting? */
358 backlight_timer = 0; /* Disable the timeout */
359 __backlight_off();
361 else
363 __backlight_on();
365 break;
367 case BACKLIGHT_OFF:
368 __backlight_off();
369 break;
371 #if (CONFIG_BACKLIGHT == BL_IRIVER_H100) && !defined(SIMULATOR)
372 case BACKLIGHT_UNBOOST_CPU:
373 cpu_boost(false);
374 break;
375 #endif
377 case SYS_USB_CONNECTED:
378 /* Tell the USB thread that we are safe */
379 DEBUGF("backlight_thread got SYS_USB_CONNECTED\n");
380 usb_acknowledge(SYS_USB_CONNECTED_ACK);
381 break;
383 case SYS_USB_DISCONNECTED:
384 usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
385 break;
390 static void backlight_tick(void)
392 #ifdef HAVE_CHARGING
393 static bool charger_was_inserted = false;
394 bool charger_is_inserted = charger_inserted();
396 if( charger_was_inserted != charger_is_inserted )
398 backlight_on();
399 #ifdef HAVE_REMOTE_LCD
400 remote_backlight_on();
401 #endif
403 charger_was_inserted = charger_is_inserted;
404 #endif /* HAVE_CHARGING */
406 if(backlight_timer)
408 backlight_timer--;
409 if(backlight_timer == 0)
411 backlight_off();
414 #ifdef HAVE_REMOTE_LCD
415 if(remote_backlight_timer)
417 remote_backlight_timer--;
418 if(remote_backlight_timer == 0)
420 remote_backlight_off();
423 #endif
426 void backlight_init(void)
428 queue_init(&backlight_queue);
429 create_thread(backlight_thread, backlight_stack,
430 sizeof(backlight_stack), backlight_thread_name);
431 tick_add_task(backlight_tick);
432 #ifdef SIMULATOR
433 /* do nothing */
434 #elif CONFIG_BACKLIGHT == BL_IRIVER_H100
435 or_l(0x00020000, &GPIO1_ENABLE);
436 or_l(0x00020000, &GPIO1_FUNCTION);
437 and_l(~0x00020000, &GPIO1_OUT); /* Start with the backlight ON */
438 #elif CONFIG_BACKLIGHT == BL_IRIVER_H300
439 or_l(0x00020000, &GPIO1_ENABLE);
440 or_l(0x00020000, &GPIO1_FUNCTION);
441 or_l(0x00020000, &GPIO1_OUT); /* Start with the backlight ON */
442 #elif CONFIG_BACKLIGHT == BL_PA14_LO || CONFIG_BACKLIGHT == BL_PA14_HI
443 PACR1 &= ~0x3000; /* Set PA14 (backlight control) to GPIO */
444 or_b(0x40, &PAIORH); /* ..and output */
445 #elif CONFIG_BACKLIGHT == BL_GMINI
446 P1CON |= 0x10; /* P1.4 C-MOS output mode */
447 #endif
448 backlight_on();
449 #ifdef HAVE_REMOTE_LCD
450 remote_backlight_on();
451 #endif
454 void backlight_on(void)
456 queue_post(&backlight_queue, BACKLIGHT_ON, NULL);
459 void backlight_off(void)
461 queue_post(&backlight_queue, BACKLIGHT_OFF, NULL);
464 /* return value in ticks; 0 means always on, <0 means always off */
465 int backlight_get_current_timeout(void)
467 #ifdef HAVE_CHARGING
468 return charger_inserted() ? backlight_timeout_plugged : backlight_timeout;
469 #else
470 return backlight_timeout;
471 #endif
474 void backlight_set_timeout(int index)
476 if((unsigned)index >= sizeof(backlight_timeout_value))
477 /* if given a weird value, use 0 */
478 index=0;
479 backlight_timeout = HZ * backlight_timeout_value[index];
480 backlight_on();
483 #ifdef HAVE_CHARGING
484 void backlight_set_timeout_plugged(int index)
486 if((unsigned)index >= sizeof(backlight_timeout_value))
487 /* if given a weird value, use 0 */
488 index=0;
489 backlight_timeout_plugged = HZ * backlight_timeout_value[index];
490 backlight_on();
492 #endif
494 #ifdef HAVE_REMOTE_LCD
495 void remote_backlight_on(void)
497 queue_post(&backlight_queue, REMOTE_BACKLIGHT_ON, NULL);
500 void remote_backlight_off(void)
502 queue_post(&backlight_queue, REMOTE_BACKLIGHT_OFF, NULL);
505 void remote_backlight_set_timeout(int index)
507 if((unsigned)index >= sizeof(backlight_timeout_value))
508 /* if given a weird value, use 0 */
509 index=0;
510 remote_backlight_timeout = HZ * backlight_timeout_value[index];
511 remote_backlight_on();
514 #ifdef HAVE_CHARGING
515 void remote_backlight_set_timeout_plugged(int index)
517 if((unsigned)index >= sizeof(backlight_timeout_value))
518 /* if given a weird value, use 0 */
519 index=0;
520 remote_backlight_timeout_plugged = HZ * backlight_timeout_value[index];
521 remote_backlight_on();
523 #endif
524 #endif /* HAVE_REMOTE_LCD */
526 #else /* no backlight, empty dummy functions */
528 #ifdef BOOTLOADER
529 void backlight_init(void)
531 #ifdef IRIVER_H300_SERIES
532 or_l(0x00020000, &GPIO1_OUT);
533 or_l(0x00020000, &GPIO1_ENABLE);
534 or_l(0x00020000, &GPIO1_FUNCTION);
535 #endif
537 #endif
539 void backlight_on(void) {}
540 void backlight_off(void) {}
541 void backlight_set_timeout(int index) {(void)index;}
542 #ifdef HAVE_REMOTE_LCD
543 void remote_backlight_on(void) {}
544 void remote_backlight_off(void) {}
545 void remote_backlight_set_timeout(int index) {(void)index;}
546 #endif
547 #endif /* #ifdef CONFIG_BACKLIGHT */
549 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
550 void backlight_set_brightness(int val)
552 /* set H300 brightness by changing the PWM
553 accepts 0..15 but note that 0 and 1 give a black display! */
554 unsigned char ucVal = (unsigned char)(val & 0x0F);
555 if(val<MIN_BRIGHTNESS_SETTING)
556 val=MIN_BRIGHTNESS_SETTING;
557 pcf50606_set_bl_pwm(ucVal);
559 #endif