blob: d5592f044768b8d5a8fe173281a1d35ac351b23e [file] [log] [blame]
Barry Wardelld4945dc2006-10-05 10:58:51 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
11 *
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)
16 *
17 *
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.
20 *
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
23 *
24 ****************************************************************************/
25
26/*
27 * Rockbox button functions
28 */
29
30#include <stdlib.h>
31#include "config.h"
32#include "cpu.h"
33#include "system.h"
34#include "button.h"
35#include "kernel.h"
36#include "backlight.h"
37#include "adc.h"
38#include "serial.h"
39#include "power.h"
40#include "system.h"
41#include "powermgmt.h"
Jens Arnoldc68e3cc2007-08-15 17:53:23 +000042#include "hwcompat.h"
Barry Wardelld4945dc2006-10-05 10:58:51 +000043
Jens Arnold7c37c542007-08-18 09:47:19 +000044static int int_btn = BUTTON_NONE;
45#ifdef IPOD_1G2G
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)
50static int wheel_timeout = 0;
51#endif
Jens Arnoldffb121c2007-07-29 08:03:21 +000052
Barry Wardelld4945dc2006-10-05 10:58:51 +000053/* iPod 3G and mini 1G, mini 2G uses iPod 4G code */
54void handle_scroll_wheel(int new_scroll, int was_hold, int reverse)
55{
56 int wheel_keycode = BUTTON_NONE;
57 static int prev_scroll = -1;
58 static int direction = 0;
59 static int count = 0;
60 static int scroll_state[4][4] = {
61 {0, 1, -1, 0},
62 {-1, 0, 0, 1},
63 {1, 0, 0, -1},
64 {0, -1, 1, 0}
65 };
Jens Arnold7c37c542007-08-18 09:47:19 +000066
67#ifdef IPOD_1G2G
68 wheel_timeout = WHEEL_TIMEOUT;
69#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +000070
71 if ( prev_scroll == -1 ) {
72 prev_scroll = new_scroll;
73 }
74 else if (direction != scroll_state[prev_scroll][new_scroll]) {
75 direction = scroll_state[prev_scroll][new_scroll];
76 count = 0;
77 }
78 else if (!was_hold) {
79 backlight_on();
Jens Arnold4012aae2007-01-19 07:33:23 +000080 reset_poweroff_timer();
Barry Wardelld4945dc2006-10-05 10:58:51 +000081 if (++count == 6) { /* reduce sensitivity */
82 count = 0;
83 switch (direction) {
84 case 1:
85 if (reverse) {
86 /* 'r' keypress */
87 wheel_keycode = BUTTON_SCROLL_FWD;
88 }
89 else {
90 /* 'l' keypress */
91 wheel_keycode = BUTTON_SCROLL_BACK;
92 }
93 break;
94 case -1:
95 if (reverse) {
96 /* 'l' keypress */
97 wheel_keycode = BUTTON_SCROLL_BACK;
98 }
99 else {
100 /* 'r' keypress */
101 wheel_keycode = BUTTON_SCROLL_FWD;
102 }
103 break;
104 default:
105 /* only happens if we get out of sync */
106 break;
107 }
108 }
109 }
110 if (wheel_keycode != BUTTON_NONE && queue_empty(&button_queue))
Michael Sevakis4b902672006-12-19 16:50:07 +0000111 queue_post(&button_queue, wheel_keycode, 0);
Barry Wardelld4945dc2006-10-05 10:58:51 +0000112 prev_scroll = new_scroll;
113}
114
115static int ipod_3g_button_read(void)
116{
117 unsigned char source, state;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000118 static bool was_hold = false;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000119 int btn = BUTTON_NONE;
Jens Arnoldb7013222007-07-27 09:57:27 +0000120
121#ifdef IPOD_3G
Jens Arnoldffb121c2007-07-29 08:03:21 +0000122 /* The following delay was 250 in the ipodlinux source,
123 * but 50 seems to work fine. 250 causes the wheel to stop
124 * working when spinning it real fast. */
125 udelay(50);
Jens Arnoldb7013222007-07-27 09:57:27 +0000126#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +0000127
128 /* get source of interupts */
129 source = GPIOA_INT_STAT;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000130
Barry Wardelld4945dc2006-10-05 10:58:51 +0000131 /* get current keypad status */
132 state = GPIOA_INPUT_VAL;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000133
134 /* toggle interrupt level */
Barry Wardelld4945dc2006-10-05 10:58:51 +0000135 GPIOA_INT_LEV = ~state;
136
Jens Arnoldb7013222007-07-27 09:57:27 +0000137#ifdef IPOD_3G
Barry Wardelld4945dc2006-10-05 10:58:51 +0000138 if (was_hold && source == 0x40 && state == 0xbf) {
139 /* ack any active interrupts */
140 GPIOA_INT_CLR = source;
141 return BUTTON_NONE;
142 }
Jens Arnoldffb121c2007-07-29 08:03:21 +0000143 was_hold = false;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000144
Barry Wardelld4945dc2006-10-05 10:58:51 +0000145 if ((state & 0x20) == 0) {
146 /* 3g hold switch is active low */
Jens Arnoldffb121c2007-07-29 08:03:21 +0000147 was_hold = true;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000148 /* hold switch on 3g causes all outputs to go low */
149 /* we shouldn't interpret these as key presses */
150 GPIOA_INT_CLR = source;
151 return BUTTON_NONE;
152 }
Jens Arnoldb7013222007-07-27 09:57:27 +0000153#elif defined IPOD_1G2G
Jens Arnoldffb121c2007-07-29 08:03:21 +0000154 if (state & 0x20) {
155 /* 1g/2g hold switch is active high */
156 GPIOA_INT_CLR = source;
157 return BUTTON_NONE;
158 }
Jens Arnoldb7013222007-07-27 09:57:27 +0000159#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +0000160 if ((state & 0x1) == 0) {
161 btn |= BUTTON_RIGHT;
162 }
163 if ((state & 0x2) == 0) {
164 btn |= BUTTON_SELECT;
165 }
166 if ((state & 0x4) == 0) {
167 btn |= BUTTON_PLAY;
168 }
169 if ((state & 0x8) == 0) {
170 btn |= BUTTON_LEFT;
171 }
172 if ((state & 0x10) == 0) {
173 btn |= BUTTON_MENU;
174 }
175
176 if (source & 0xc0) {
177 handle_scroll_wheel((state & 0xc0) >> 6, was_hold, 0);
178 }
179
180 /* ack any active interrupts */
181 GPIOA_INT_CLR = source;
182
183 return btn;
184}
185
Jens Arnoldffb121c2007-07-29 08:03:21 +0000186void ipod_3g_button_int(void)
187{
188 CPU_INT_CLR = GPIO_MASK;
189 int_btn = ipod_3g_button_read();
190 CPU_INT_EN = GPIO_MASK;
191}
192
Barry Wardelld4945dc2006-10-05 10:58:51 +0000193void button_init_device(void)
194{
Jens Arnoldffb121c2007-07-29 08:03:21 +0000195 GPIOA_ENABLE = 0xff;
196 GPIOA_OUTPUT_EN = 0;
197
Barry Wardelld4945dc2006-10-05 10:58:51 +0000198 GPIOA_INT_LEV = ~GPIOA_INPUT_VAL;
199 GPIOA_INT_CLR = GPIOA_INT_STAT;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000200
Jens Arnoldc68e3cc2007-08-15 17:53:23 +0000201#ifdef IPOD_1G2G
202 if ((IPOD_HW_REVISION >> 16) == 1)
203 { /* enable scroll wheel */
204 GPIOB_ENABLE |= 0x01;
205 GPIOB_OUTPUT_EN |= 0x01;
206 GPIOB_OUTPUT_VAL |= 0x01;
207 }
208#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +0000209 GPIOA_INT_EN = 0xff;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000210
211 CPU_INT_EN = GPIO_MASK;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000212}
213
214/*
215 * Get button pressed from hardware
216 */
217int button_read_device(void)
218{
219 static bool hold_button = false;
220 bool hold_button_old;
Jens Arnold7c37c542007-08-18 09:47:19 +0000221#ifdef IPOD_1G2G
222 static unsigned char last_wheel_value = 0;
223 unsigned char wheel_value;
224
225 if ((IPOD_HW_REVISION >> 16) == 1)
226 {
227 if (!hold_button && (wheel_timeout == 0))
228 {
229 GPIOB_OUTPUT_VAL |= 0x01; /* enable wheel */
230 udelay(50); /* let the voltage settle */
231 wheel_value = GPIOA_INPUT_VAL >> 6;
232 if (wheel_value != last_wheel_value)
233 {
234 last_wheel_value = wheel_value;
235 wheel_timeout = WHEEL_TIMEOUT; /* keep wheel enabled */
236 }
237 }
238 if (wheel_timeout)
239 wheel_timeout--;
240 else
241 GPIOB_OUTPUT_VAL &= ~0x01; /* disable wheel */
242 }
243#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +0000244
245 /* normal buttons */
246 hold_button_old = hold_button;
247 hold_button = button_hold();
248
249 if (hold_button != hold_button_old)
250 backlight_hold_changed(hold_button);
Jens Arnold7c37c542007-08-18 09:47:19 +0000251
Jens Arnoldffb121c2007-07-29 08:03:21 +0000252 return int_btn;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000253}
254
255bool button_hold(void)
256{
Jens Arnold021c0862007-07-27 12:05:54 +0000257#ifdef IPOD_1G2G
258 return (GPIOA_INPUT_VAL & 0x20);
259#else
260 return !(GPIOA_INPUT_VAL & 0x20);
261#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +0000262}
Daniel Ankers5c6f32a2006-10-07 12:19:34 +0000263
264bool headphones_inserted(void)
265{
266 return (GPIOC_INPUT_VAL & 0x1)?true:false;
267}