1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Daniel Stenberg
12 * iPod driver based on code from the ipodlinux project - http://ipodlinux.org
13 * Adapted for Rockbox in December 2005
14 * Original file: linux/arch/armnommu/mach-ipod/keyboard.c
15 * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org)
18 * All files in this archive are subject to the GNU General Public License.
19 * See the file COPYING in the source tree root for full license agreement.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 ****************************************************************************/
27 * Rockbox button functions
36 #include "backlight.h"
41 #include "powermgmt.h"
43 struct event_queue button_queue
;
45 static long lastbtn
; /* Last valid button status */
46 static long last_read
; /* Last button status, for debouncing/filtering */
47 #ifdef HAVE_LCD_BITMAP
48 static bool flipped
; /* buttons can be flipped to match the LCD flip */
51 /* how often we check to see if a button is pressed */
52 #define POLL_FREQUENCY HZ/100
54 /* how long until repeat kicks in */
55 #define REPEAT_START 30
57 /* the speed repeat starts at */
58 #define REPEAT_INTERVAL_START 16
60 /* speed repeat finishes at */
61 #define REPEAT_INTERVAL_FINISH 5
63 /* the power-off button and number of repeated keys before shutting off */
64 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IRIVER_IFP7XX_PAD)
65 #define POWEROFF_BUTTON BUTTON_PLAY
66 #define POWEROFF_COUNT 40
68 #define POWEROFF_BUTTON BUTTON_OFF
69 #define POWEROFF_COUNT 10
72 static int button_read(void);
74 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
75 static bool remote_button_hold_only(void);
78 #if CONFIG_KEYPAD == IPOD_4G_PAD
79 /* Variable to use for setting button status in interrupt handler */
80 int int_btn
= BUTTON_NONE
;
82 static void opto_i2c_init(void)
86 /* wait for value to settle */
88 curr_value
= (inl(0x7000c104) << 16) >> 24;
91 int new_value
= (inl(0x7000c104) << 16) >> 24;
93 if (new_value
!= curr_value
) {
95 curr_value
= new_value
;
102 GPIOB_OUTPUT_VAL
|= 0x10;
106 DEV_RS
&= ~0x10000; /* finish reset */
108 outl(0xffffffff, 0x7000c120);
109 outl(0xffffffff, 0x7000c124);
110 outl(0xc00a1f00, 0x7000c100);
111 outl(0x1000000, 0x7000c104);
114 static int ipod_4g_button_read(void)
116 unsigned reg
, status
;
117 static int clickwheel_down
= 0;
118 static int old_wheel_value
= -1;
119 int wheel_keycode
= BUTTON_NONE
;
120 int wheel_delta
, wheel_delta_abs
;
122 int btn
= BUTTON_NONE
;
124 /* The ipodlinux source had a udelay(250) here, but testing has shown that
125 it is not needed - tested on Nano, Color/Photo and Video. */
129 if ((inl(0x7000c104) & 0x4000000) != 0) {
130 reg
= reg
+ 0x3C; /* 0x7000c140 */
132 status
= inl(0x7000c140);
133 outl(0x0, 0x7000c140); /* clear interrupt status? */
135 if ((status
& 0x800000ff) == 0x8000001a) {
136 /* NB: highest wheel = 0x5F, clockwise increases */
137 new_wheel_value
= ((status
<< 9) >> 25) & 0xff;
140 btn
|= BUTTON_SELECT
;
149 if (status
& 0x40000000) {
150 /* scroll wheel down */
153 if (old_wheel_value
!= -1) {
154 wheel_delta
= new_wheel_value
- old_wheel_value
;
155 wheel_delta_abs
= wheel_delta
< 0 ? -wheel_delta
158 if (wheel_delta_abs
> 48) {
159 if (old_wheel_value
> new_wheel_value
)
160 /* wrapped around the top going clockwise */
162 else if (old_wheel_value
< new_wheel_value
)
163 /* wrapped around the top going counterclockwise */ wheel_delta
-= 96;
165 /* TODO: these thresholds should most definitely be
166 settings, and we're probably going to want a more
167 advanced scheme than this anyway. */
168 if (wheel_delta
> 4) {
169 wheel_keycode
= BUTTON_SCROLL_FWD
;
170 old_wheel_value
= new_wheel_value
;
171 } else if (wheel_delta
< -4) {
172 wheel_keycode
= BUTTON_SCROLL_BACK
;
173 old_wheel_value
= new_wheel_value
;
176 if (wheel_keycode
!= BUTTON_NONE
)
177 queue_post(&button_queue
, wheel_keycode
, NULL
);
180 old_wheel_value
= new_wheel_value
;
183 else if (clickwheel_down
) {
184 /* scroll wheel up */
185 old_wheel_value
= -1;
190 Don't know why this should be needed, let me know if you do.
191 else if ((status & 0x800000FF) == 0x8000003A) {
192 wheel_value = status & 0x800000FF;
195 else if (status
== 0xffffffff) {
200 if ((inl(reg
) & 0x8000000) != 0) {
201 outl(0xffffffff, 0x7000c120);
202 outl(0xffffffff, 0x7000c124);
207 void ipod_4g_button_int(void)
209 CPU_HI_INT_CLR
= I2C_MASK
;
210 /* The following delay was 250 in the ipodlinux source, but 10 seems to
211 work fine - tested on Nano, Color/Photo and Video. */
213 outl(0x0, 0x7000c140);
214 int_btn
= ipod_4g_button_read();
215 outl(inl(0x7000c104) | 0xC000000, 0x7000c104);
216 outl(0x400a1f00, 0x7000c100);
218 GPIOB_OUTPUT_VAL
|= 0x10;
219 CPU_INT_EN
= 0x40000000;
220 CPU_HI_INT_EN
= I2C_MASK
;
224 static void button_tick(void)
227 static int count
= 0;
228 static int repeat_speed
= REPEAT_INTERVAL_START
;
229 static int repeat_count
= 0;
230 static bool repeat
= false;
234 #if (CONFIG_KEYPAD == PLAYER_PAD) || (CONFIG_KEYPAD == RECORDER_PAD)
236 /* Post events for the remote control */
237 btn
= remote_control_rx();
240 queue_post(&button_queue
, btn
, NULL
);
244 /* only poll every X ticks */
245 if ( ++tick
>= POLL_FREQUENCY
)
250 /* Find out if a key has been released */
251 diff
= btn
^ lastbtn
;
252 if(diff
&& (btn
& diff
) == 0)
254 queue_post(&button_queue
, BUTTON_REL
| diff
, NULL
);
260 /* normal keypress */
261 if ( btn
!= lastbtn
)
265 repeat_speed
= REPEAT_INTERVAL_START
;
275 /* yes we have repeat */
277 if (repeat_speed
< REPEAT_INTERVAL_FINISH
)
278 repeat_speed
= REPEAT_INTERVAL_FINISH
;
279 count
= repeat_speed
;
283 /* Send a SYS_POWEROFF event if we have a device
284 which doesn't shut down easily with the OFF
286 #ifdef HAVE_SW_POWEROFF
287 #ifdef BUTTON_RC_STOP
288 if ((btn
== POWEROFF_BUTTON
|| btn
== BUTTON_RC_STOP
) &&
290 if (btn
== POWEROFF_BUTTON
&&
292 #if defined(HAVE_CHARGING) && !defined(HAVE_POWEROFF_WHILE_CHARGING)
293 !charger_inserted() &&
295 repeat_count
> POWEROFF_COUNT
)
297 /* Tell the main thread that it's time to
301 /* Safety net for players without hardware
303 if(repeat_count
> POWEROFF_COUNT
* 10)
311 if (count
++ > REPEAT_START
)
317 count
= REPEAT_INTERVAL_START
;
324 queue_post(&button_queue
, BUTTON_REPEAT
| btn
, NULL
);
326 queue_post(&button_queue
, btn
, NULL
);
327 #ifdef HAVE_REMOTE_LCD
328 if(btn
& BUTTON_REMOTE
)
329 remote_backlight_on();
334 reset_poweroff_timer();
343 lastbtn
= btn
& ~(BUTTON_REL
| BUTTON_REPEAT
);
348 long button_get(bool block
)
352 if ( block
|| !queue_empty(&button_queue
) )
354 queue_wait(&button_queue
, &ev
);
360 long button_get_w_tmo(int ticks
)
363 queue_wait_w_tmo(&button_queue
, &ev
, ticks
);
364 return (ev
.id
!= SYS_TIMEOUT
)? ev
.id
: BUTTON_NONE
;
367 void button_init(void)
370 #if CONFIG_KEYPAD == IRIVER_H100_PAD
371 /* Set GPIO33, GPIO37, GPIO38 and GPIO52 as general purpose inputs */
372 GPIO1_FUNCTION
|= 0x00100062;
373 GPIO1_ENABLE
&= ~0x00100060;
374 #elif CONFIG_KEYPAD == IRIVER_H300_PAD
375 /* Set GPIO9 and GPIO15 as general purpose inputs */
376 GPIO_ENABLE
&= ~0x00008200;
377 GPIO_FUNCTION
|= 0x00008200;
378 /* Set GPIO33, GPIO37, GPIO38 and GPIO52 as general purpose inputs */
379 GPIO1_ENABLE
&= ~0x00100060;
380 GPIO1_FUNCTION
|= 0x00100062;
381 #elif CONFIG_KEYPAD == RECORDER_PAD
382 /* Set PB4 and PB8 as input pins */
383 PBCR1
&= 0xfffc; /* PB8MD = 00 */
384 PBCR2
&= 0xfcff; /* PB4MD = 00 */
385 PBIOR
&= ~0x0110; /* Inputs */
386 #elif CONFIG_KEYPAD == PLAYER_PAD
387 /* set PA5 and PA11 as input pins */
388 PACR1
&= 0xff3f; /* PA11MD = 00 */
389 PACR2
&= 0xfbff; /* PA5MD = 0 */
390 PAIOR
&= ~0x0820; /* Inputs */
391 #elif CONFIG_KEYPAD == ONDIO_PAD
392 /* nothing to initialize here */
393 #elif CONFIG_KEYPAD == GMINI100_PAD
394 /* nothing to initialize here */
395 #elif CONFIG_KEYPAD == IPOD_4G_PAD
397 /* hold button - enable as input */
398 GPIOA_ENABLE
|= 0x20;
399 GPIOA_OUTPUT_EN
&= ~0x20;
400 /* hold button - set interrupt levels */
401 GPIOA_INT_LEV
= ~(GPIOA_INPUT_VAL
& 0x20);
402 GPIOA_INT_CLR
= GPIOA_INT_STAT
& 0x20;
403 /* enable interrupts */
405 CPU_INT_EN
= 0x40000000;
406 CPU_HI_INT_EN
= I2C_MASK
;
407 #endif /* CONFIG_KEYPAD */
409 queue_init(&button_queue
);
411 lastbtn
= button_read();
412 tick_add_task(button_tick
);
413 reset_poweroff_timer();
415 #ifdef HAVE_LCD_BITMAP
420 #ifdef HAVE_LCD_BITMAP /* only bitmap displays can be flipped */
421 #if (CONFIG_KEYPAD != IPOD_4G_PAD)
423 * helper function to swap UP/DOWN, LEFT/RIGHT (and F1/F3 for Recorder)
425 static int button_flip(int button
)
430 ~(BUTTON_UP
| BUTTON_DOWN
431 | BUTTON_LEFT
| BUTTON_RIGHT
432 #if CONFIG_KEYPAD == RECORDER_PAD
433 | BUTTON_F1
| BUTTON_F3
437 if (button
& BUTTON_UP
)
438 newbutton
|= BUTTON_DOWN
;
439 if (button
& BUTTON_DOWN
)
440 newbutton
|= BUTTON_UP
;
441 if (button
& BUTTON_LEFT
)
442 newbutton
|= BUTTON_RIGHT
;
443 if (button
& BUTTON_RIGHT
)
444 newbutton
|= BUTTON_LEFT
;
445 #if CONFIG_KEYPAD == RECORDER_PAD
446 if (button
& BUTTON_F1
)
447 newbutton
|= BUTTON_F3
;
448 if (button
& BUTTON_F3
)
449 newbutton
|= BUTTON_F1
;
455 /* We don't flip the iPod's keypad yet*/
456 #define button_flip(x) (x)
460 * set the flip attribute
461 * better only call this when the queue is empty
463 void button_set_flip(bool flip
)
465 if (flip
!= flipped
) /* not the current setting */
467 /* avoid race condition with the button_tick() */
468 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
469 lastbtn
= button_flip(lastbtn
);
471 set_irq_level(oldlevel
);
474 #endif /* HAVE_LCD_BITMAP */
477 Archos hardware button hookup
478 =============================
480 Recorder / Recorder FM/V2
481 -------------------------
482 F1, F2, F3, UP: connected to AN4 through a resistor network
483 DOWN, PLAY, LEFT, RIGHT: likewise connected to AN5
485 The voltage on AN4/ AN5 depends on which keys (or key combo) is pressed
486 FM/V2 has PLAY and RIGHT switched compared to plain recorder
488 ON: PB8, low active (plain recorder) / AN3, low active (fm/v2)
489 OFF: PB4, low active (plain recorder) / AN2, high active (fm/v2)
501 All buttons are low active
505 LEFT, RIGHT, UP, DOWN: connected to AN4 through a resistor network
507 The voltage on AN4 depends on which keys (or key combo) is pressed
509 OPTION: AN2, high active (assigned as MENU)
510 ON/OFF: AN3, low active (assigned as OFF)
514 #if CONFIG_KEYPAD == RECORDER_PAD
517 /* FM Recorder super-special levels */
522 #define ROW2_BUTTON1 BUTTON_PLAY
523 #define ROW2_BUTTON3 BUTTON_RIGHT
526 /* plain bog standard Recorder levels */
531 #define ROW2_BUTTON1 BUTTON_RIGHT
532 #define ROW2_BUTTON3 BUTTON_PLAY
533 #endif /* HAVE_FMADC */
535 #elif CONFIG_KEYPAD == ONDIO_PAD
542 #endif /* CONFIG_KEYPAD */
545 * Get button pressed from hardware
547 static int button_read(void)
549 int btn
= BUTTON_NONE
;
554 #if CONFIG_KEYPAD == IRIVER_H100_PAD
556 static bool hold_button
= false;
557 static bool remote_hold_button
= false;
560 if (hold_button
&& !button_hold())
564 if (remote_hold_button
&& !remote_button_hold_only())
566 remote_backlight_on();
569 hold_button
= button_hold();
570 remote_hold_button
= remote_button_hold_only();
575 data
= adc_scan(ADC_BUTTONS
);
603 if (!remote_hold_button
)
605 data
= adc_scan(ADC_REMOTE
);
611 btn
= BUTTON_RC_STOP
;
613 btn
= BUTTON_RC_VOL_DOWN
;
615 btn
= BUTTON_RC_MODE
;
618 btn
= BUTTON_RC_VOL_UP
;
620 btn
= BUTTON_RC_BITRATE
;
626 btn
= BUTTON_RC_SOURCE
;
632 btn
= BUTTON_RC_MENU
;
638 /* special buttons */
640 if (!hold_button
&& ((data
& 0x20) == 0))
642 if (!remote_hold_button
&& ((data
& 0x40) == 0))
645 #elif CONFIG_KEYPAD == IRIVER_H300_PAD
647 static bool hold_button
= false;
648 static bool remote_hold_button
= false;
651 if (hold_button
&& !button_hold())
655 if (remote_hold_button
&& !remote_button_hold_only())
657 remote_backlight_on();
660 hold_button
= button_hold();
661 remote_hold_button
= remote_button_hold_only();
666 data
= adc_scan(ADC_BUTTONS
);
688 if (!remote_hold_button
)
690 data
= adc_scan(ADC_REMOTE
);
696 btn
= BUTTON_RC_STOP
;
698 btn
= BUTTON_RC_VOL_DOWN
;
700 btn
= BUTTON_RC_MODE
;
703 btn
= BUTTON_RC_VOL_UP
;
705 btn
= BUTTON_RC_BITRATE
;
711 btn
= BUTTON_RC_SOURCE
;
717 btn
= BUTTON_RC_MENU
;
723 /* special buttons */
727 if ((data
& 0x0200) == 0)
729 if ((data
& 0x8000) == 0)
734 if (!hold_button
&& ((data
& 0x20) == 0))
736 if (!remote_hold_button
&& ((data
& 0x40) == 0))
739 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
741 static bool hold_button
= false;
744 if (hold_button
&& !button_hold())
748 hold_button
= button_hold();
753 data
= adc_read(ADC_BUTTONS
);
777 if (!button_hold() && (adc_read(ADC_BUTTON_PLAY
) < 0x64))
780 #elif CONFIG_KEYPAD == RECORDER_PAD
783 if ( adc_read(ADC_BUTTON_ON
) < 512 )
785 if ( adc_read(ADC_BUTTON_OFF
) > 512 )
788 /* check port B pins for ON and OFF */
790 if ((data
& 0x0100) == 0)
792 if ((data
& 0x0010) == 0)
796 /* check F1..F3 and UP */
797 data
= adc_read(ADC_BUTTON_ROW1
);
801 else if (data
>= LEVEL3
)
803 else if (data
>= LEVEL2
)
805 else if (data
>= LEVEL1
)
808 /* Some units have mushy keypads, so pressing UP also activates
809 the Left/Right buttons. Let's combat that by skipping the AN5
810 checks when UP is pressed. */
811 if(!(btn
& BUTTON_UP
))
813 /* check DOWN, PLAY, LEFT, RIGHT */
814 data
= adc_read(ADC_BUTTON_ROW2
);
818 else if (data
>= LEVEL3
)
820 else if (data
>= LEVEL2
)
822 else if (data
>= LEVEL1
)
826 #elif CONFIG_KEYPAD == PLAYER_PAD
828 /* buttons are active low */
829 if (adc_read(0) < 0x180)
831 if (adc_read(1) < 0x180)
833 if(adc_read(2) < 0x180)
835 if(adc_read(3) < 0x180)
838 /* check port A pins for ON and STOP */
840 if ( !(data
& 0x0020) )
842 if ( !(data
& 0x0800) )
845 #elif CONFIG_KEYPAD == ONDIO_PAD
847 if(adc_read(ADC_BUTTON_OPTION
) > 0x200) /* active high */
849 if(adc_read(ADC_BUTTON_ONOFF
) < 0x120) /* active low */
852 /* Check the 4 direction keys */
853 data
= adc_read(ADC_BUTTON_ROW1
);
857 else if (data
>= LEVEL3
)
859 else if (data
>= LEVEL2
)
861 else if (data
>= LEVEL1
)
864 #elif CONFIG_KEYPAD == GMINI100_PAD
866 if (adc_read(7) < 0xE3)
868 else if (adc_read(7) < 0x1c5)
870 else if (adc_read(7) < 0x2a2)
872 else if (adc_read(7) < 0x38a)
875 if (adc_read(6) < 0x233)
877 else if (adc_read(6) < 0x288)
879 else if (adc_read(6) < 0x355)
886 #elif CONFIG_KEYPAD == IPOD_4G_PAD
888 /* The int_btn variable is set in the button interrupt handler */
890 #endif /* CONFIG_KEYPAD */
893 #ifdef HAVE_LCD_BITMAP
895 btn
= button_flip(btn
); /* swap upside down */
898 /* Filter the button status. It is only accepted if we get the same
899 status twice in a row. */
900 if (btn
!= last_read
)
909 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
910 bool button_hold(void)
912 return (GPIO1_READ
& 0x00000002)?true:false;
915 static bool remote_button_hold_only(void)
917 return (GPIO1_READ
& 0x00100000)?true:false;
920 bool remote_button_hold(void)
922 return ((GPIO_READ
& 0x40000000) == 0)?remote_button_hold_only():false;
926 #if CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
927 bool button_hold(void)
929 return (GPIO5_READ
& 4) ? false : true;
933 int button_status(void)
938 void button_clear_queue(void)
940 queue_clear(&button_queue
);