summaryrefslogtreecommitdiff
path: root/firmware/target/arm/ipod/button-clickwheel.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/ipod/button-clickwheel.c')
-rw-r--r--firmware/target/arm/ipod/button-clickwheel.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/firmware/target/arm/ipod/button-clickwheel.c b/firmware/target/arm/ipod/button-clickwheel.c
new file mode 100644
index 0000000000..4c536343c4
--- /dev/null
+++ b/firmware/target/arm/ipod/button-clickwheel.c
@@ -0,0 +1,237 @@
1/***************************************************************************
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"
42
43/* Variable to use for setting button status in interrupt handler */
44int int_btn = BUTTON_NONE;
45#ifdef HAVE_WHEEL_POSITION
46 static int wheel_position = -1;
47 static bool send_events = true;
48#endif
49
50static void opto_i2c_init(void)
51{
52 int i, curr_value;
53
54 /* wait for value to settle */
55 i = 1000;
56 curr_value = (inl(0x7000c104) << 16) >> 24;
57 while (i > 0)
58 {
59 int new_value = (inl(0x7000c104) << 16) >> 24;
60
61 if (new_value != curr_value) {
62 i = 10000;
63 curr_value = new_value;
64 }
65 else {
66 i--;
67 }
68 }
69
70 GPIOB_OUTPUT_VAL |= 0x10;
71 DEV_EN |= 0x10000;
72 DEV_RS |= 0x10000;
73 udelay(5);
74 DEV_RS &= ~0x10000; /* finish reset */
75
76 outl(0xffffffff, 0x7000c120);
77 outl(0xffffffff, 0x7000c124);
78 outl(0xc00a1f00, 0x7000c100);
79 outl(0x1000000, 0x7000c104);
80}
81
82static inline int ipod_4g_button_read(void)
83{
84 int whl = -1;
85
86 /* The ipodlinux source had a udelay(250) here, but testing has shown that
87 it is not needed - tested on Nano, Color/Photo and Video. */
88 /* udelay(250);*/
89
90 int btn = BUTTON_NONE;
91 unsigned reg = 0x7000c104;
92 if ((inl(0x7000c104) & 0x4000000) != 0) {
93 unsigned status = inl(0x7000c140);
94
95 reg = reg + 0x3C; /* 0x7000c140 */
96 outl(0x0, 0x7000c140); /* clear interrupt status? */
97
98 if ((status & 0x800000ff) == 0x8000001a) {
99 static int old_wheel_value IDATA_ATTR = -1;
100 static int wheel_repeat = 0;
101
102 if (status & 0x100)
103 btn |= BUTTON_SELECT;
104 if (status & 0x200)
105 btn |= BUTTON_RIGHT;
106 if (status & 0x400)
107 btn |= BUTTON_LEFT;
108 if (status & 0x800)
109 btn |= BUTTON_PLAY;
110 if (status & 0x1000)
111 btn |= BUTTON_MENU;
112 if (status & 0x40000000) {
113 /* NB: highest wheel = 0x5F, clockwise increases */
114 int new_wheel_value = (status << 9) >> 25;
115 whl = new_wheel_value;
116 backlight_on();
117 /* The queue should have no other events when scrolling */
118 if (queue_empty(&button_queue) && old_wheel_value >= 0) {
119
120 /* This is for later = BUTTON_SCROLL_TOUCH;*/
121 int wheel_delta = new_wheel_value - old_wheel_value;
122 unsigned long data;
123 int wheel_keycode;
124
125 if (wheel_delta < -48)
126 wheel_delta += 96; /* Forward wrapping case */
127 else if (wheel_delta > 48)
128 wheel_delta -= 96; /* Backward wrapping case */
129
130 if (wheel_delta > 4) {
131 wheel_keycode = BUTTON_SCROLL_FWD;
132 } else if (wheel_delta < -4) {
133 wheel_keycode = BUTTON_SCROLL_BACK;
134 } else goto wheel_end;
135
136#ifdef HAVE_WHEEL_POSITION
137 if (send_events)
138#endif
139 {
140 data = (wheel_delta << 16) | new_wheel_value;
141 queue_post(&button_queue, wheel_keycode | wheel_repeat,
142 (void *)data);
143 }
144
145 if (!wheel_repeat) wheel_repeat = BUTTON_REPEAT;
146 }
147
148 old_wheel_value = new_wheel_value;
149 } else if (old_wheel_value >= 0) {
150 /* scroll wheel up */
151 old_wheel_value = -1;
152 wheel_repeat = 0;
153 }
154
155 } else if (status == 0xffffffff) {
156 opto_i2c_init();
157 }
158 }
159
160wheel_end:
161
162 if ((inl(reg) & 0x8000000) != 0) {
163 outl(0xffffffff, 0x7000c120);
164 outl(0xffffffff, 0x7000c124);
165 }
166 /* Save the new absolute wheel position */
167 wheel_position = whl;
168 return btn;
169}
170
171#ifdef HAVE_WHEEL_POSITION
172int wheel_status(void)
173{
174 return wheel_position;
175}
176
177void wheel_send_events(bool send)
178{
179 send_events = send;
180}
181#endif
182
183void ipod_4g_button_int(void)
184{
185 CPU_HI_INT_CLR = I2C_MASK;
186 /* The following delay was 250 in the ipodlinux source, but 50 seems to
187 work fine - tested on Nano, Color/Photo and Video. */
188 udelay(50);
189 outl(0x0, 0x7000c140);
190 int_btn = ipod_4g_button_read();
191 outl(inl(0x7000c104) | 0xC000000, 0x7000c104);
192 outl(0x400a1f00, 0x7000c100);
193
194 GPIOB_OUTPUT_VAL |= 0x10;
195 CPU_INT_EN = 0x40000000;
196 CPU_HI_INT_EN = I2C_MASK;
197}
198
199void button_init_device(void)
200{
201 opto_i2c_init();
202 /* hold button - enable as input */
203 GPIOA_ENABLE |= 0x20;
204 GPIOA_OUTPUT_EN &= ~0x20;
205 /* hold button - set interrupt levels */
206 GPIOA_INT_LEV = ~(GPIOA_INPUT_VAL & 0x20);
207 GPIOA_INT_CLR = GPIOA_INT_STAT & 0x20;
208 /* enable interrupts */
209 GPIOA_INT_EN = 0x20;
210 /* unmask interrupt */
211 CPU_INT_EN = 0x40000000;
212 CPU_HI_INT_EN = I2C_MASK;
213}
214
215/*
216 * Get button pressed from hardware
217 */
218int button_read_device(void)
219{
220 static bool hold_button = false;
221 bool hold_button_old;
222
223 /* normal buttons */
224 hold_button_old = hold_button;
225 hold_button = button_hold();
226
227 if (hold_button != hold_button_old)
228 backlight_hold_changed(hold_button);
229
230 /* The int_btn variable is set in the button interrupt handler */
231 return int_btn;
232}
233
234bool button_hold(void)
235{
236 return (GPIOA_INPUT_VAL & 0x20)?false:true;
237}