Move declaration of button_int and clickwheel_int to the proper header file instead...
[Rockbox.git] / firmware / target / arm / sandisk / sansa-e200 / button-e200.c
blob21c0c376e1dd68b17764873efbbc9f2d2ea6f2cc
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Barry Wardell
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 /* Taken from button-h10.c by Barry Wardell and reverse engineering by MrH. */
24 #include "system.h"
25 #include "button.h"
26 #include "backlight.h"
27 #include "powermgmt.h"
29 #define WHEEL_REPEAT_INTERVAL 300000
30 #define WHEEL_FAST_ON_INTERVAL 20000
31 #define WHEEL_FAST_OFF_INTERVAL 60000
32 #define WHEELCLICKS_PER_ROTATION 48 /* wheelclicks per full rotation */
34 /* Clickwheel */
35 #ifndef BOOTLOADER
36 static unsigned int old_wheel_value = 0;
37 static unsigned int wheel_repeat = BUTTON_NONE;
38 static unsigned int wheel_click_count = 0;
39 static unsigned int wheel_delta = 0;
40 static int wheel_fast_mode = 0;
41 static unsigned long last_wheel_usec = 0;
42 static unsigned long wheel_velocity = 0;
43 static long last_wheel_post = 0;
44 static long next_backlight_on = 0;
45 /* Buttons */
46 static bool hold_button = false;
47 static bool hold_button_old = false;
48 #define _button_hold() hold_button
49 #else
50 #define _button_hold() ((GPIOF_INPUT_VAL & 0x80) != 0)
51 #endif /* BOOTLOADER */
52 static int int_btn = BUTTON_NONE;
54 void button_init_device(void)
56 /* Enable all buttons */
57 GPIOF_OUTPUT_EN &= ~0xff;
58 GPIOF_ENABLE |= 0xff;
60 /* Scrollwheel light - enable control through GPIOG pin 7 and set timeout */
61 GPIOG_OUTPUT_EN |= 0x80;
62 GPIOG_ENABLE = 0x80;
64 #ifndef BOOTLOADER
65 /* Mask these before performing init ... because init has possibly
66 occurred before */
67 GPIOF_INT_EN &= ~0xff;
68 GPIOH_INT_EN &= ~0xc0;
70 /* Get current tick before enabling button interrupts */
71 last_wheel_usec = USEC_TIMER;
72 last_wheel_post = last_wheel_usec;
74 GPIOH_ENABLE |= 0xc0;
75 GPIOH_OUTPUT_EN &= ~0xc0;
77 /* Read initial buttons */
78 button_int();
79 GPIOF_INT_CLR = 0xff;
81 /* Read initial wheel value (bit 6-7 of GPIOH) */
82 old_wheel_value = GPIOH_INPUT_VAL & 0xc0;
83 GPIOH_INT_LEV = (GPIOH_INT_LEV & ~0xc0) | (old_wheel_value ^ 0xc0);
84 GPIOH_INT_CLR = 0xc0;
86 /* Enable button interrupts */
87 GPIOF_INT_EN |= 0xff;
88 GPIOH_INT_EN |= 0xc0;
90 CPU_INT_EN = HI_MASK;
91 CPU_HI_INT_EN = GPIO1_MASK;
92 #endif /* BOOTLOADER */
95 bool button_hold(void)
97 return _button_hold();
100 /* clickwheel */
101 #ifndef BOOTLOADER
102 void clickwheel_int(void)
104 /* Read wheel
105 * Bits 6 and 7 of GPIOH change as follows:
106 * Clockwise rotation 01 -> 00 -> 10 -> 11
107 * Counter-clockwise 11 -> 10 -> 00 -> 01
109 * This is equivalent to wheel_value of:
110 * Clockwise rotation 0x40 -> 0x00 -> 0x80 -> 0xc0
111 * Counter-clockwise 0xc0 -> 0x80 -> 0x00 -> 0x40
113 static const unsigned char wheel_tbl[2][4] =
115 /* 0x00 0x40 0x80 0xc0 */ /* Wheel value */
116 { 0x40, 0xc0, 0x00, 0x80 }, /* Clockwise rotation */
117 { 0x80, 0x00, 0xc0, 0x40 }, /* Counter-clockwise */
120 unsigned int wheel_value;
122 wheel_value = GPIOH_INPUT_VAL & 0xc0;
123 GPIOH_INT_LEV = (GPIOH_INT_LEV & ~0xc0) | (wheel_value ^ 0xc0);
124 GPIOH_INT_CLR = GPIOH_INT_STAT & 0xc0;
126 if (!hold_button)
128 unsigned int btn = BUTTON_NONE;
130 if (old_wheel_value == wheel_tbl[0][wheel_value >> 6])
131 btn = BUTTON_SCROLL_FWD;
132 else if (old_wheel_value == wheel_tbl[1][wheel_value >> 6])
133 btn = BUTTON_SCROLL_BACK;
135 if (btn != BUTTON_NONE)
137 int repeat = 1; /* assume repeat */
138 unsigned long usec = USEC_TIMER;
139 unsigned v = (usec - last_wheel_usec) & 0x7fffffff;
141 v = (v>0) ? 1000000 / v : 0; /* clicks/sec = 1000000 * clicks/usec */
142 v = (v>0xffffff) ? 0xffffff : v; /* limit to 24 bit */
144 /* some velocity filtering to smooth things out */
145 wheel_velocity = (7*wheel_velocity + v) / 8;
147 if (btn != wheel_repeat)
149 /* direction reversals nullify all fast mode states */
150 wheel_repeat = btn;
151 repeat =
152 wheel_fast_mode =
153 wheel_velocity =
154 wheel_click_count = 0;
157 if (wheel_fast_mode != 0)
159 /* fast OFF happens immediately when velocity drops below
160 threshold */
161 if (TIME_AFTER(usec,
162 last_wheel_usec + WHEEL_FAST_OFF_INTERVAL))
164 /* moving out of fast mode */
165 wheel_fast_mode = 0;
166 /* reset velocity */
167 wheel_velocity = 0;
168 /* wheel_delta is always 1 in slow mode */
169 wheel_delta = 1;
172 else
174 /* fast ON gets filtered to avoid inadvertent jumps to fast mode */
175 if (repeat && wheel_velocity > 1000000/WHEEL_FAST_ON_INTERVAL)
177 /* moving into fast mode */
178 wheel_fast_mode = 1 << 31;
179 wheel_click_count = 0;
180 wheel_velocity = 1000000/WHEEL_FAST_OFF_INTERVAL;
182 else if (++wheel_click_count < 2)
184 btn = BUTTON_NONE;
187 /* wheel_delta is always 1 in slow mode */
188 wheel_delta = 1;
191 if (TIME_AFTER(current_tick, next_backlight_on) ||
192 v <= 4)
194 /* poke backlight to turn it on or maintain it no more often
195 than every 1/4 second*/
196 next_backlight_on = current_tick + HZ/4;
197 backlight_on();
198 buttonlight_on();
199 reset_poweroff_timer();
202 if (btn != BUTTON_NONE)
204 wheel_click_count = 0;
206 /* generate repeats if quick enough */
207 if (repeat && TIME_BEFORE(usec,
208 last_wheel_post + WHEEL_REPEAT_INTERVAL))
209 btn |= BUTTON_REPEAT;
211 last_wheel_post = usec;
213 if (queue_empty(&button_queue))
215 queue_post(&button_queue, btn, wheel_fast_mode |
216 (wheel_delta << 24) | wheel_velocity*360/WHEELCLICKS_PER_ROTATION);
217 /* message posted - reset delta */
218 wheel_delta = 1;
220 else
222 /* skipped post - increment delta */
223 if (++wheel_delta > 0x7f)
224 wheel_delta = 0x7f;
228 last_wheel_usec = usec;
232 old_wheel_value = wheel_value;
234 #endif /* BOOTLOADER */
236 /* device buttons */
237 void button_int(void)
239 unsigned char state;
241 int_btn = BUTTON_NONE;
243 state = GPIOF_INPUT_VAL & 0xff;
245 #ifndef BOOTLOADER
246 GPIOF_INT_LEV = (GPIOF_INT_LEV & ~0xff) | (state ^ 0xff);
247 GPIOF_INT_CLR = GPIOF_INT_STAT;
249 hold_button = (state & 0x80) != 0;
250 #endif
252 if (!_button_hold())
254 /* Read normal buttons */
255 if ((state & 0x01) == 0) int_btn |= BUTTON_REC;
256 if ((state & 0x02) == 0) int_btn |= BUTTON_DOWN;
257 if ((state & 0x04) == 0) int_btn |= BUTTON_RIGHT;
258 if ((state & 0x08) == 0) int_btn |= BUTTON_LEFT;
259 if ((state & 0x10) == 0) int_btn |= BUTTON_SELECT; /* The centre button */
260 if ((state & 0x20) == 0) int_btn |= BUTTON_UP; /* The "play" button */
261 if ((state & 0x40) != 0) int_btn |= BUTTON_POWER;
266 * Get button pressed from hardware
268 int button_read_device(void)
270 #ifdef BOOTLOADER
271 /* Read buttons directly in the bootloader */
272 button_int();
273 #else
274 /* light handling */
275 if (hold_button != hold_button_old)
277 hold_button_old = hold_button;
278 backlight_hold_changed(hold_button);
280 #endif /* BOOTLOADER */
282 /* The int_btn variable is set in the button interrupt handler */
283 return int_btn;