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 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
26 ****************************************************************************/
29 * Rockbox button functions
38 #include "backlight.h"
41 #include "powermgmt.h"
44 static int int_btn
= BUTTON_NONE
;
46 /* The 1st Gen wheel draws ~12mA when enabled permanently. Therefore
47 * we only enable it for a very short time to check for changes every
48 * tick, and only keep it enabled if there is activity. */
49 #define WHEEL_TIMEOUT (HZ/4)
52 static void handle_scroll_wheel(int new_scroll
, int was_hold
)
54 int wheel_keycode
= BUTTON_NONE
;
55 static int prev_scroll
= -1;
56 static int direction
= 0;
58 static int scroll_state
[4][4] = {
65 if ( prev_scroll
== -1 ) {
66 prev_scroll
= new_scroll
;
68 else if (direction
!= scroll_state
[prev_scroll
][new_scroll
]) {
69 direction
= scroll_state
[prev_scroll
][new_scroll
];
74 reset_poweroff_timer();
75 if (++count
== 6) { /* reduce sensitivity */
77 /* 1st..3rd Gen wheel has inverse direction mapping
78 * compared to Mini 1st Gen wheel. */
81 wheel_keycode
= BUTTON_SCROLL_BACK
;
84 wheel_keycode
= BUTTON_SCROLL_FWD
;
87 /* only happens if we get out of sync */
92 if (wheel_keycode
!= BUTTON_NONE
&& queue_empty(&button_queue
))
93 queue_post(&button_queue
, wheel_keycode
, 0);
94 prev_scroll
= new_scroll
;
97 static int ipod_3g_button_read(void)
99 unsigned char source
, state
;
100 static bool was_hold
= false;
101 int btn
= BUTTON_NONE
;
104 /* The following delay was 250 in the ipodlinux source,
105 * but 50 seems to work fine. 250 causes the wheel to stop
106 * working when spinning it real fast. */
110 /* get source of interupts */
111 source
= GPIOA_INT_STAT
;
113 /* get current keypad status */
114 state
= GPIOA_INPUT_VAL
;
116 /* toggle interrupt level */
117 GPIOA_INT_LEV
= ~state
;
120 if (was_hold
&& source
== 0x40 && state
== 0xbf) {
121 /* ack any active interrupts */
122 GPIOA_INT_CLR
= source
;
127 if ((state
& 0x20) == 0) {
128 /* 3g hold switch is active low */
130 /* hold switch on 3g causes all outputs to go low */
131 /* we shouldn't interpret these as key presses */
132 GPIOA_INT_CLR
= source
;
135 #elif defined IPOD_1G2G
137 /* 1g/2g hold switch is active high */
138 GPIOA_INT_CLR
= source
;
142 if ((state
& 0x1) == 0) {
145 if ((state
& 0x2) == 0) {
146 btn
|= BUTTON_SELECT
;
148 if ((state
& 0x4) == 0) {
151 if ((state
& 0x8) == 0) {
154 if ((state
& 0x10) == 0) {
159 handle_scroll_wheel((state
& 0xc0) >> 6, was_hold
);
162 /* ack any active interrupts */
163 GPIOA_INT_CLR
= source
;
168 void ipod_3g_button_int(void)
170 CPU_INT_DIS
= GPIO_MASK
;
171 int_btn
= ipod_3g_button_read();
172 CPU_INT_EN
= GPIO_MASK
;
175 void button_init_device(void)
180 GPIOA_INT_LEV
= ~GPIOA_INPUT_VAL
;
181 GPIOA_INT_CLR
= GPIOA_INT_STAT
;
184 if ((IPOD_HW_REVISION
>> 16) == 1)
185 { /* enable scroll wheel */
186 GPIOB_ENABLE
|= 0x01;
187 GPIOB_OUTPUT_EN
|= 0x01;
188 GPIOB_OUTPUT_VAL
|= 0x01;
193 CPU_INT_EN
= GPIO_MASK
;
197 * Get button pressed from hardware
199 int button_read_device(void)
201 static bool hold_button
= false;
202 bool hold_button_old
;
204 static int wheel_timeout
= 0;
205 static unsigned char last_wheel_value
= 0;
206 unsigned char wheel_value
;
208 if ((IPOD_HW_REVISION
>> 16) == 1)
210 if (!hold_button
&& (wheel_timeout
== 0))
212 GPIOB_OUTPUT_VAL
|= 0x01; /* enable wheel */
213 udelay(50); /* let the voltage settle */
215 wheel_value
= GPIOA_INPUT_VAL
>> 6;
216 if (wheel_value
!= last_wheel_value
)
218 last_wheel_value
= wheel_value
;
219 wheel_timeout
= WHEEL_TIMEOUT
; /* keep wheel enabled */
220 GPIOA_INT_EN
= 0xff; /* enable wheel interrupts */
226 GPIOA_INT_EN
= 0x3f; /* disable wheel interrupts */
227 GPIOB_OUTPUT_VAL
&= ~0x01; /* disable wheel */
233 hold_button_old
= hold_button
;
234 hold_button
= button_hold();
236 if (hold_button
!= hold_button_old
)
237 backlight_hold_changed(hold_button
);
242 bool button_hold(void)
245 return (GPIOA_INPUT_VAL
& 0x20);
247 return !(GPIOA_INPUT_VAL
& 0x20);
251 bool headphones_inserted(void)
254 if ((IPOD_HW_REVISION
>> 16) == 2)
256 /* 2G uses GPIO B bit 0 */
257 return (GPIOB_INPUT_VAL
& 0x1)?true:false;
261 /* 1G has no headphone detection, so fake insertion */
265 /* 3G uses GPIO C bit 0 */
266 return (GPIOC_INPUT_VAL
& 0x1)?true:false;