blob: 56c0a8afa022c4e81249c19a5f359854a3262454 [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 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000018 * 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.
Barry Wardelld4945dc2006-10-05 10:58:51 +000022 *
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
25 *
26 ****************************************************************************/
27
28/*
29 * Rockbox button functions
30 */
31
32#include <stdlib.h>
33#include "config.h"
34#include "cpu.h"
35#include "system.h"
36#include "button.h"
37#include "kernel.h"
38#include "backlight.h"
39#include "adc.h"
40#include "serial.h"
41#include "power.h"
42#include "system.h"
43#include "powermgmt.h"
Jens Arnoldc68e3cc2007-08-15 17:53:23 +000044#include "hwcompat.h"
Barry Wardelld4945dc2006-10-05 10:58:51 +000045
Jens Arnold7c37c542007-08-18 09:47:19 +000046static int int_btn = BUTTON_NONE;
47#ifdef IPOD_1G2G
48/* The 1st Gen wheel draws ~12mA when enabled permanently. Therefore
49 * we only enable it for a very short time to check for changes every
50 * tick, and only keep it enabled if there is activity. */
51#define WHEEL_TIMEOUT (HZ/4)
Jens Arnold7c37c542007-08-18 09:47:19 +000052#endif
Jens Arnoldffb121c2007-07-29 08:03:21 +000053
Jens Arnolde249ecc2008-04-01 17:52:22 +000054static void handle_scroll_wheel(int new_scroll, int was_hold)
Barry Wardelld4945dc2006-10-05 10:58:51 +000055{
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
Barry Wardelld4945dc2006-10-05 10:58:51 +000067 if ( prev_scroll == -1 ) {
68 prev_scroll = new_scroll;
69 }
70 else if (direction != scroll_state[prev_scroll][new_scroll]) {
71 direction = scroll_state[prev_scroll][new_scroll];
72 count = 0;
73 }
74 else if (!was_hold) {
75 backlight_on();
Jens Arnold4012aae2007-01-19 07:33:23 +000076 reset_poweroff_timer();
Barry Wardelld4945dc2006-10-05 10:58:51 +000077 if (++count == 6) { /* reduce sensitivity */
78 count = 0;
Jens Arnolde249ecc2008-04-01 17:52:22 +000079 /* 1st..3rd Gen wheel has inverse direction mapping
80 * compared to Mini 1st Gen wheel. */
Barry Wardelld4945dc2006-10-05 10:58:51 +000081 switch (direction) {
82 case 1:
Jens Arnolde249ecc2008-04-01 17:52:22 +000083 wheel_keycode = BUTTON_SCROLL_BACK;
Barry Wardelld4945dc2006-10-05 10:58:51 +000084 break;
85 case -1:
Jens Arnolde249ecc2008-04-01 17:52:22 +000086 wheel_keycode = BUTTON_SCROLL_FWD;
Barry Wardelld4945dc2006-10-05 10:58:51 +000087 break;
88 default:
89 /* only happens if we get out of sync */
90 break;
91 }
92 }
93 }
94 if (wheel_keycode != BUTTON_NONE && queue_empty(&button_queue))
Michael Sevakis4b902672006-12-19 16:50:07 +000095 queue_post(&button_queue, wheel_keycode, 0);
Barry Wardelld4945dc2006-10-05 10:58:51 +000096 prev_scroll = new_scroll;
97}
98
99static int ipod_3g_button_read(void)
100{
101 unsigned char source, state;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000102 static bool was_hold = false;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000103 int btn = BUTTON_NONE;
Jens Arnoldb7013222007-07-27 09:57:27 +0000104
105#ifdef IPOD_3G
Jens Arnoldffb121c2007-07-29 08:03:21 +0000106 /* The following delay was 250 in the ipodlinux source,
107 * but 50 seems to work fine. 250 causes the wheel to stop
108 * working when spinning it real fast. */
109 udelay(50);
Jens Arnoldb7013222007-07-27 09:57:27 +0000110#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +0000111
112 /* get source of interupts */
113 source = GPIOA_INT_STAT;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000114
Barry Wardelld4945dc2006-10-05 10:58:51 +0000115 /* get current keypad status */
116 state = GPIOA_INPUT_VAL;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000117
118 /* toggle interrupt level */
Barry Wardelld4945dc2006-10-05 10:58:51 +0000119 GPIOA_INT_LEV = ~state;
120
Jens Arnoldb7013222007-07-27 09:57:27 +0000121#ifdef IPOD_3G
Barry Wardelld4945dc2006-10-05 10:58:51 +0000122 if (was_hold && source == 0x40 && state == 0xbf) {
123 /* ack any active interrupts */
124 GPIOA_INT_CLR = source;
125 return BUTTON_NONE;
126 }
Jens Arnoldffb121c2007-07-29 08:03:21 +0000127 was_hold = false;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000128
Barry Wardelld4945dc2006-10-05 10:58:51 +0000129 if ((state & 0x20) == 0) {
130 /* 3g hold switch is active low */
Jens Arnoldffb121c2007-07-29 08:03:21 +0000131 was_hold = true;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000132 /* hold switch on 3g causes all outputs to go low */
133 /* we shouldn't interpret these as key presses */
134 GPIOA_INT_CLR = source;
135 return BUTTON_NONE;
136 }
Jens Arnoldb7013222007-07-27 09:57:27 +0000137#elif defined IPOD_1G2G
Jens Arnoldffb121c2007-07-29 08:03:21 +0000138 if (state & 0x20) {
139 /* 1g/2g hold switch is active high */
140 GPIOA_INT_CLR = source;
141 return BUTTON_NONE;
142 }
Jens Arnoldb7013222007-07-27 09:57:27 +0000143#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +0000144 if ((state & 0x1) == 0) {
145 btn |= BUTTON_RIGHT;
146 }
147 if ((state & 0x2) == 0) {
148 btn |= BUTTON_SELECT;
149 }
150 if ((state & 0x4) == 0) {
151 btn |= BUTTON_PLAY;
152 }
153 if ((state & 0x8) == 0) {
154 btn |= BUTTON_LEFT;
155 }
156 if ((state & 0x10) == 0) {
157 btn |= BUTTON_MENU;
158 }
159
160 if (source & 0xc0) {
Jens Arnolde249ecc2008-04-01 17:52:22 +0000161 handle_scroll_wheel((state & 0xc0) >> 6, was_hold);
Barry Wardelld4945dc2006-10-05 10:58:51 +0000162 }
163
164 /* ack any active interrupts */
165 GPIOA_INT_CLR = source;
166
167 return btn;
168}
169
Jens Arnoldffb121c2007-07-29 08:03:21 +0000170void ipod_3g_button_int(void)
171{
Michael Sevakis191320c2008-06-03 05:08:24 +0000172 CPU_INT_DIS = GPIO_MASK;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000173 int_btn = ipod_3g_button_read();
174 CPU_INT_EN = GPIO_MASK;
175}
176
Barry Wardelld4945dc2006-10-05 10:58:51 +0000177void button_init_device(void)
178{
Jens Arnoldffb121c2007-07-29 08:03:21 +0000179 GPIOA_ENABLE = 0xff;
180 GPIOA_OUTPUT_EN = 0;
181
Barry Wardelld4945dc2006-10-05 10:58:51 +0000182 GPIOA_INT_LEV = ~GPIOA_INPUT_VAL;
183 GPIOA_INT_CLR = GPIOA_INT_STAT;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000184
Jens Arnoldc68e3cc2007-08-15 17:53:23 +0000185#ifdef IPOD_1G2G
186 if ((IPOD_HW_REVISION >> 16) == 1)
187 { /* enable scroll wheel */
188 GPIOB_ENABLE |= 0x01;
189 GPIOB_OUTPUT_EN |= 0x01;
190 GPIOB_OUTPUT_VAL |= 0x01;
191 }
192#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +0000193 GPIOA_INT_EN = 0xff;
Jens Arnoldffb121c2007-07-29 08:03:21 +0000194
195 CPU_INT_EN = GPIO_MASK;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000196}
197
198/*
199 * Get button pressed from hardware
200 */
201int button_read_device(void)
202{
203 static bool hold_button = false;
204 bool hold_button_old;
Jens Arnold7c37c542007-08-18 09:47:19 +0000205#ifdef IPOD_1G2G
Jens Arnolde249ecc2008-04-01 17:52:22 +0000206 static int wheel_timeout = 0;
Jens Arnold7c37c542007-08-18 09:47:19 +0000207 static unsigned char last_wheel_value = 0;
208 unsigned char wheel_value;
209
210 if ((IPOD_HW_REVISION >> 16) == 1)
211 {
212 if (!hold_button && (wheel_timeout == 0))
213 {
214 GPIOB_OUTPUT_VAL |= 0x01; /* enable wheel */
215 udelay(50); /* let the voltage settle */
Jens Arnolde249ecc2008-04-01 17:52:22 +0000216 }
217 wheel_value = GPIOA_INPUT_VAL >> 6;
218 if (wheel_value != last_wheel_value)
219 {
220 last_wheel_value = wheel_value;
221 wheel_timeout = WHEEL_TIMEOUT; /* keep wheel enabled */
Jens Arnold1f75bd52008-04-01 18:53:34 +0000222 GPIOA_INT_EN = 0xff; /* enable wheel interrupts */
Jens Arnolde249ecc2008-04-01 17:52:22 +0000223 }
Jens Arnold7c37c542007-08-18 09:47:19 +0000224 if (wheel_timeout)
225 wheel_timeout--;
226 else
Jens Arnolde249ecc2008-04-01 17:52:22 +0000227 {
228 GPIOA_INT_EN = 0x3f; /* disable wheel interrupts */
Jens Arnold7c37c542007-08-18 09:47:19 +0000229 GPIOB_OUTPUT_VAL &= ~0x01; /* disable wheel */
Jens Arnolde249ecc2008-04-01 17:52:22 +0000230 }
Jens Arnold7c37c542007-08-18 09:47:19 +0000231 }
232#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +0000233
234 /* normal buttons */
235 hold_button_old = hold_button;
236 hold_button = button_hold();
237
238 if (hold_button != hold_button_old)
239 backlight_hold_changed(hold_button);
Jens Arnold7c37c542007-08-18 09:47:19 +0000240
Jens Arnoldffb121c2007-07-29 08:03:21 +0000241 return int_btn;
Barry Wardelld4945dc2006-10-05 10:58:51 +0000242}
243
244bool button_hold(void)
245{
Jens Arnold021c0862007-07-27 12:05:54 +0000246#ifdef IPOD_1G2G
247 return (GPIOA_INPUT_VAL & 0x20);
248#else
249 return !(GPIOA_INPUT_VAL & 0x20);
250#endif
Barry Wardelld4945dc2006-10-05 10:58:51 +0000251}
Daniel Ankers5c6f32a2006-10-07 12:19:34 +0000252
253bool headphones_inserted(void)
254{
Michael Giacomellie243db62008-05-03 21:15:13 +0000255#ifdef IPOD_1G2G
Michael Giacomelli5fc95a32008-05-03 22:07:31 +0000256 if ((IPOD_HW_REVISION >> 16) == 2)
Michael Giacomellie243db62008-05-03 21:15:13 +0000257 {
Michael Giacomelli5fc95a32008-05-03 22:07:31 +0000258 /* 2G uses GPIO B bit 0 */
259 return (GPIOB_INPUT_VAL & 0x1)?true:false;
Michael Giacomellie243db62008-05-03 21:15:13 +0000260 }
Michael Giacomelli5fc95a32008-05-03 22:07:31 +0000261 else
Michael Giacomellie243db62008-05-03 21:15:13 +0000262 {
Michael Giacomelli5fc95a32008-05-03 22:07:31 +0000263 /* 1G has no headphone detection, so fake insertion */
264 return (true);
Michael Giacomellie243db62008-05-03 21:15:13 +0000265 }
266#else
267 /* 3G uses GPIO C bit 0 */
Daniel Ankers5c6f32a2006-10-07 12:19:34 +0000268 return (GPIOC_INPUT_VAL & 0x1)?true:false;
Michael Giacomellie243db62008-05-03 21:15:13 +0000269#endif
Daniel Ankers5c6f32a2006-10-07 12:19:34 +0000270}
Michael Giacomellie243db62008-05-03 21:15:13 +0000271
272