More iPod 3G work from Seven Le Mesle
[Rockbox.git] / firmware / backlight.c
blob1a7ea8e7f073370a53630326b6e43e3fca1e8803
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) || (CONFIG_BACKLIGHT == BL_IPOD3G)
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_IPODMINI
240 /* set port B03 on */
241 outl(((0x100 | 1) << 3), 0x6000d824);
242 #elif CONFIG_BACKLIGHT==BL_IPODNANO
243 /* set port B03 on */
244 outl(((0x100 | 1) << 3), 0x6000d824);
246 /* set port L07 on */
247 outl(((0x100 | 1) << 7), 0x6000d12c);
248 #elif CONFIG_BACKLIGHT==BL_IPOD3G
249 lcd_enable(true);
250 #elif CONFIG_BACKLIGHT==BL_IRIVER_IFP7XX
251 GPIO3_SET = 1;
252 #endif
255 static void __backlight_off(void)
257 #ifdef SIMULATOR
258 sim_backlight(0);
259 #elif CONFIG_BACKLIGHT == BL_IRIVER_H100
260 if (fade_out_count > 0)
261 backlight_dim(0);
262 else
264 bl_dim_target = bl_dim_current = 0;
265 or_l(0x00020000, &GPIO1_OUT);
267 #elif CONFIG_BACKLIGHT == BL_IRIVER_H300
268 and_l(~0x00020000, &GPIO1_OUT);
269 lcd_enable(false);
270 #elif CONFIG_BACKLIGHT == BL_RTC
271 /* Disable square wave */
272 rtc_write(0x0a, rtc_read(0x0a) & ~0x40);
273 #elif CONFIG_BACKLIGHT == BL_PA14_LO /* Player */
274 and_b(~0x40, &PAIORH); /* let it float (up) */
275 #elif CONFIG_BACKLIGHT == BL_PA14_HI /* Ondio */
276 and_b(~0x40, &PADRH); /* drive it low */
277 #elif CONFIG_BACKLIGHT == BL_GMINI
278 P1 &= ~0x10;
279 #elif CONFIG_BACKLIGHT == BL_IPOD4G
280 /* fades backlight off on 4g */
281 outl(inl(0x70000084) & ~0x2000000, 0x70000084);
282 outl(0x80000000, 0x7000a010);
283 #elif CONFIG_BACKLIGHT==BL_IPODNANO
284 /* set port B03 off */
285 outl(((0x100 | 0) << 3), 0x6000d824);
287 /* set port L07 off */
288 outl(((0x100 | 0) << 7), 0x6000d12c);
289 #elif CONFIG_BACKLIGHT==BL_IRIVER_IFP7XX
290 GPIO3_CLR = 1;
291 #elif CONFIG_BACKLIGHT==BL_IPOD3G
292 lcd_enable(false);
293 #elif CONFIG_BACKLIGHT==BL_IPODMINI
294 /* set port B03 off */
295 outl(((0x100 | 0) << 3), 0x6000d824);
296 #endif
299 #ifdef HAVE_REMOTE_LCD
300 static void __remote_backlight_on(void)
302 #ifdef SIMULATOR
303 sim_remote_backlight(100);
304 #elif defined(IRIVER_H300_SERIES)
305 and_l(~0x00000002, &GPIO1_OUT);
306 #else
307 and_l(~0x00000800, &GPIO_OUT);
308 #endif
311 static void __remote_backlight_off(void)
313 #ifdef SIMULATOR
314 sim_remote_backlight(0);
315 #elif defined(IRIVER_H300_SERIES)
316 or_l(0x00000002, &GPIO1_OUT);
317 #else
318 or_l(0x00000800, &GPIO_OUT);
319 #endif
321 #endif /* HAVE_REMOTE_LCD */
323 void backlight_thread(void)
325 struct event ev;
327 while(1)
329 queue_wait(&backlight_queue, &ev);
330 switch(ev.id)
332 #ifdef HAVE_REMOTE_LCD
333 case REMOTE_BACKLIGHT_ON:
334 #ifdef HAVE_CHARGING
335 if (charger_inserted())
336 remote_backlight_timer = remote_backlight_timeout_plugged;
337 else
338 #endif
339 remote_backlight_timer = remote_backlight_timeout;
341 /* Backlight == OFF in the setting? */
342 if (remote_backlight_timer < 0)
344 remote_backlight_timer = 0; /* Disable the timeout */
345 __remote_backlight_off();
347 else
349 __remote_backlight_on();
351 break;
353 case REMOTE_BACKLIGHT_OFF:
354 __remote_backlight_off();
355 break;
357 #endif /* HAVE_REMOTE_LCD */
358 case BACKLIGHT_ON:
359 #ifdef HAVE_CHARGING
360 if (charger_inserted())
361 backlight_timer = backlight_timeout_plugged;
362 else
363 #endif
364 backlight_timer = backlight_timeout;
366 if (backlight_timer < 0) /* Backlight == OFF in the setting? */
368 backlight_timer = 0; /* Disable the timeout */
369 __backlight_off();
371 else
373 __backlight_on();
375 break;
377 case BACKLIGHT_OFF:
378 __backlight_off();
379 break;
381 #if (CONFIG_BACKLIGHT == BL_IRIVER_H100) && !defined(SIMULATOR)
382 case BACKLIGHT_UNBOOST_CPU:
383 cpu_boost(false);
384 break;
385 #endif
387 case SYS_USB_CONNECTED:
388 /* Tell the USB thread that we are safe */
389 DEBUGF("backlight_thread got SYS_USB_CONNECTED\n");
390 usb_acknowledge(SYS_USB_CONNECTED_ACK);
391 break;
393 case SYS_USB_DISCONNECTED:
394 usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
395 break;
400 static void backlight_tick(void)
402 #ifdef HAVE_CHARGING
403 static bool charger_was_inserted = false;
404 bool charger_is_inserted = charger_inserted();
406 if( charger_was_inserted != charger_is_inserted )
408 backlight_on();
409 #ifdef HAVE_REMOTE_LCD
410 remote_backlight_on();
411 #endif
413 charger_was_inserted = charger_is_inserted;
414 #endif /* HAVE_CHARGING */
416 if(backlight_timer)
418 backlight_timer--;
419 if(backlight_timer == 0)
421 backlight_off();
424 #ifdef HAVE_REMOTE_LCD
425 if(remote_backlight_timer)
427 remote_backlight_timer--;
428 if(remote_backlight_timer == 0)
430 remote_backlight_off();
433 #endif
436 void backlight_init(void)
438 queue_init(&backlight_queue);
439 create_thread(backlight_thread, backlight_stack,
440 sizeof(backlight_stack), backlight_thread_name);
441 tick_add_task(backlight_tick);
442 #ifdef SIMULATOR
443 /* do nothing */
444 #elif CONFIG_BACKLIGHT == BL_IRIVER_H100
445 or_l(0x00020000, &GPIO1_ENABLE);
446 or_l(0x00020000, &GPIO1_FUNCTION);
447 and_l(~0x00020000, &GPIO1_OUT); /* Start with the backlight ON */
448 #elif CONFIG_BACKLIGHT == BL_IRIVER_H300
449 or_l(0x00020000, &GPIO1_ENABLE);
450 or_l(0x00020000, &GPIO1_FUNCTION);
451 or_l(0x00020000, &GPIO1_OUT); /* Start with the backlight ON */
452 #elif CONFIG_BACKLIGHT == BL_PA14_LO || CONFIG_BACKLIGHT == BL_PA14_HI
453 PACR1 &= ~0x3000; /* Set PA14 (backlight control) to GPIO */
454 or_b(0x40, &PAIORH); /* ..and output */
455 #elif CONFIG_BACKLIGHT == BL_GMINI
456 P1CON |= 0x10; /* P1.4 C-MOS output mode */
457 #endif
458 backlight_on();
459 #ifdef HAVE_REMOTE_LCD
460 remote_backlight_on();
461 #endif
464 void backlight_on(void)
466 queue_post(&backlight_queue, BACKLIGHT_ON, NULL);
469 void backlight_off(void)
471 queue_post(&backlight_queue, BACKLIGHT_OFF, NULL);
474 /* return value in ticks; 0 means always on, <0 means always off */
475 int backlight_get_current_timeout(void)
477 #ifdef HAVE_CHARGING
478 return charger_inserted() ? backlight_timeout_plugged : backlight_timeout;
479 #else
480 return backlight_timeout;
481 #endif
484 void backlight_set_timeout(int index)
486 if((unsigned)index >= sizeof(backlight_timeout_value))
487 /* if given a weird value, use 0 */
488 index=0;
489 backlight_timeout = HZ * backlight_timeout_value[index];
490 backlight_on();
493 #ifdef HAVE_CHARGING
494 void backlight_set_timeout_plugged(int index)
496 if((unsigned)index >= sizeof(backlight_timeout_value))
497 /* if given a weird value, use 0 */
498 index=0;
499 backlight_timeout_plugged = HZ * backlight_timeout_value[index];
500 backlight_on();
502 #endif
504 #ifdef HAVE_REMOTE_LCD
505 void remote_backlight_on(void)
507 queue_post(&backlight_queue, REMOTE_BACKLIGHT_ON, NULL);
510 void remote_backlight_off(void)
512 queue_post(&backlight_queue, REMOTE_BACKLIGHT_OFF, NULL);
515 void remote_backlight_set_timeout(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 = HZ * backlight_timeout_value[index];
521 remote_backlight_on();
524 #ifdef HAVE_CHARGING
525 void remote_backlight_set_timeout_plugged(int index)
527 if((unsigned)index >= sizeof(backlight_timeout_value))
528 /* if given a weird value, use 0 */
529 index=0;
530 remote_backlight_timeout_plugged = HZ * backlight_timeout_value[index];
531 remote_backlight_on();
533 #endif
534 #endif /* HAVE_REMOTE_LCD */
536 #else /* no backlight, empty dummy functions */
538 #ifdef BOOTLOADER
539 void backlight_init(void)
541 #ifdef IRIVER_H300_SERIES
542 or_l(0x00020000, &GPIO1_OUT);
543 or_l(0x00020000, &GPIO1_ENABLE);
544 or_l(0x00020000, &GPIO1_FUNCTION);
545 #endif
547 #endif
549 void backlight_on(void) {}
550 void backlight_off(void) {}
551 void backlight_set_timeout(int index) {(void)index;}
552 #ifdef HAVE_REMOTE_LCD
553 void remote_backlight_on(void) {}
554 void remote_backlight_off(void) {}
555 void remote_backlight_set_timeout(int index) {(void)index;}
556 #endif
557 #endif /* #ifdef CONFIG_BACKLIGHT */
559 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
560 #ifdef IRIVER_H300_SERIES
561 void backlight_set_brightness(int val)
563 /* set H300 brightness by changing the PWM
564 accepts 0..15 but note that 0 and 1 give a black display! */
565 val &= 0x0F;
566 if(val<MIN_BRIGHTNESS_SETTING)
567 val=MIN_BRIGHTNESS_SETTING;
569 /* shift one bit left */
570 val <<= 1;
572 /* enable PWM */
573 val |= 0x01;
575 /* disable IRQs while bitbanging */
576 int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
578 pcf50606_write(0x35, val);
580 /* enable IRQs again */
581 set_irq_level(old_irq_level);
583 #endif
584 #endif