summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c')
-rw-r--r--firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c192
1 files changed, 180 insertions, 12 deletions
diff --git a/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c b/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
index db08414ae5..9421076cce 100644
--- a/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
+++ b/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
@@ -24,37 +24,198 @@
24#include "button.h" 24#include "button.h"
25#include "backlight.h" 25#include "backlight.h"
26 26
27extern void scrollwheel(unsigned wheel_value);
28
29#ifdef HAS_BUTTON_HOLD 27#ifdef HAS_BUTTON_HOLD
30static bool hold_button = false; 28static bool hold_button = false;
31#endif 29#endif
30
31#ifdef HAVE_SCROLLWHEEL
32#define SCROLLWHEEL_BITS (1<<7|1<<6)
33 /* TIMER units */
34#define TIMER_TICK (TIMER_FREQ/HZ) /* how long a tick lasts */
35#define TIMER_MS (TIMER_TICK/(1000/HZ))/* how long a ms lasts */
36
37#define WHEEL_REPEAT_INTERVAL (300*TIMER_MS) /* 300ms */
38#define WHEEL_FAST_ON_INTERVAL ( 20*TIMER_MS) /* 20ms */
39#define WHEEL_FAST_OFF_INTERVAL ( 60*TIMER_MS) /* 60ms */
40/* phsyical clicks per rotation * wheel value changes per phys click */
41#define WHEEL_CHANGES_PER_CLICK 4
42#define WHEELCLICKS_PER_ROTATION (12*WHEEL_CHANGES_PER_CLICK)
43
44/*
45 * based on button-e200.c, adjusted to the AMS timers and fuzev2's
46 * scrollwheel and cleaned up a little
47 */
48static void scrollwheel(unsigned int wheel_value)
49{
50 /* wheel values and times from the previous irq */
51 static unsigned int old_wheel_value = 0;
52 static unsigned int wheel_repeat = BUTTON_NONE;
53 static long last_wheel_post = 0;
54
55 /* We only post every 4th action, as this matches better with the physical
56 * clicks of the wheel */
57 static unsigned int wheel_click_count = 0;
58 /* number of items to skip in lists, 1 in slow mode */
59 static unsigned int wheel_delta = 0;
60 /* accumulated wheel rotations per second */
61 static unsigned long wheel_velocity = 0;
62 /* fast or slow mode? */
63 static int wheel_fast_mode = 0;
64
65 /* Read wheel
66 * Bits 6 and 7 of GPIOA change as follows (Gray Code):
67 * Clockwise rotation 00 -> 01 -> 11 -> 10 -> 00
68 * Counter-clockwise 00 -> 10 -> 11 -> 01 -> 00
69 *
70 * For easy look-up, actual wheel values act as indicies also,
71 * which is why the table seems to be not ordered correctly
72 */
73 static const unsigned char wheel_tbl[2][4] =
74 {
75 { 2, 0, 3, 1 }, /* Clockwise rotation */
76 { 1, 3, 0, 2 }, /* Counter-clockwise */
77 };
78
79 unsigned int btn = BUTTON_NONE;
80
81 if (old_wheel_value == wheel_tbl[0][wheel_value])
82 btn = BUTTON_SCROLL_FWD;
83 else if (old_wheel_value == wheel_tbl[1][wheel_value])
84 btn = BUTTON_SCROLL_BACK;
85
86 if (btn == BUTTON_NONE)
87 {
88 old_wheel_value = wheel_value;
89 return;
90 }
91
92 int repeat = 1; /* assume repeat */
93 long time = TIMER1_VALUE + current_tick*TIMER_TICK; /* to timer unit */
94 long v = (time - last_wheel_post);
95
96 /* interpolate velocity in timer_freq/timer_unit == 1/s */
97 if (v) v = TIMER_FREQ / v;
98
99 /* accumulate velocities over time with each v */
100 wheel_velocity = (7*wheel_velocity + v) / 8;
101
102 if (btn != wheel_repeat)
103 {
104 /* direction reversals nullify all fast mode states */
105 wheel_repeat = btn;
106 repeat =
107 wheel_velocity =
108 wheel_click_count = 0;
109 }
110
111 if (wheel_fast_mode != 0)
112 {
113 /* fast OFF happens immediately when velocity drops below
114 threshold */
115 if (TIME_AFTER(time,
116 last_wheel_post + WHEEL_FAST_OFF_INTERVAL))
117 {
118 /* moving out of fast mode */
119 wheel_fast_mode = 0;
120 /* reset velocity */
121 wheel_velocity = 0;
122 /* wheel_delta is always 1 in slow mode */
123 wheel_delta = 1;
124 }
125 }
126 else
127 {
128 /* fast ON gets filtered to avoid inadvertent jumps to fast mode */
129 if (repeat && wheel_velocity > TIMER_FREQ/WHEEL_FAST_ON_INTERVAL)
130 {
131 /* moving into fast mode */
132 wheel_fast_mode = 1 << 31;
133 wheel_click_count = 0;
134 wheel_velocity = TIMER_FREQ/WHEEL_FAST_OFF_INTERVAL;
135 }
136 else if (++wheel_click_count < WHEEL_CHANGES_PER_CLICK)
137 { /* skip some wheel changes, so that 1 post represents
138 * 1 item in lists */
139 btn = BUTTON_NONE;
140 }
141
142 /* wheel_delta is always 1 in slow mode */
143 wheel_delta = 1;
144 }
145
146 if (btn != BUTTON_NONE)
147 {
148 wheel_click_count = 0;
149
150 /* generate repeats if quick enough */
151 if (repeat && TIME_BEFORE(time,
152 last_wheel_post + WHEEL_REPEAT_INTERVAL))
153 btn |= BUTTON_REPEAT;
154
155 last_wheel_post = time;
156
157 if (queue_empty(&button_queue))
158 {
159 queue_post(&button_queue, btn, wheel_fast_mode |
160 (wheel_delta << 24) | wheel_velocity*360/WHEELCLICKS_PER_ROTATION);
161 /* message posted - reset delta and poke backlight on*/
162 wheel_delta = 1;
163 backlight_on();
164 buttonlight_on();
165 }
166 else
167 {
168 /* skipped post - increment delta */
169 if (++wheel_delta > 0x7f)
170 wheel_delta = 0x7f;
171 }
172 }
173
174 old_wheel_value = wheel_value;
175}
176#endif
177
32void button_init_device(void) 178void button_init_device(void)
33{ 179{
180#if defined(HAVE_SCROLLWHEEL)
34 GPIOA_DIR &= ~(1<<6|1<<7); 181 GPIOA_DIR &= ~(1<<6|1<<7);
35 GPIOC_DIR = 0; 182 GPIOC_DIR = 0;
36 GPIOB_DIR |= (1<<4)|(1<<0); 183 GPIOB_DIR |= (1<<4)|(1<<0);
37 184
38 GPIOB_PIN(4) = 1<<4; /* activate the wheel */ 185 GPIOB_PIN(4) = 1<<4; /* activate the wheel */
39}
40 186
41void get_scrollwheel(void) 187 /* setup scrollwheel isr */
42{ 188 /* clear previous irq if any */
43#if defined(HAVE_SCROLLWHEEL) && !defined(BOOTLOADER) 189 GPIOA_IC = SCROLLWHEEL_BITS;
44 /* scroll wheel handling */ 190 /* enable edge detecting */
191 GPIOA_IS &= ~SCROLLWHEEL_BITS;
192 /* detect both raising and falling edges */
193 GPIOA_IBE |= SCROLLWHEEL_BITS;
194 /* lastly, enable the interrupt */
195 GPIOA_IE |= SCROLLWHEEL_BITS;
196#endif
197}
45 198
199 /* read the 2 bits at the same time */
46#define GPIOA_PIN76_offset ((1<<(6+2)) | (1<<(7+2))) 200#define GPIOA_PIN76_offset ((1<<(6+2)) | (1<<(7+2)))
47#define GPIOA_PIN76 (*(volatile unsigned char*)(GPIOA_BASE+GPIOA_PIN76_offset)) 201#define GPIOA_PIN76 (*(volatile unsigned char*)(GPIOA_BASE+GPIOA_PIN76_offset))
48 scrollwheel(GPIOA_PIN76 >> 6);
49 202
203void button_gpioa_isr(void)
204{
205#if defined(HAVE_SCROLLWHEEL)
206 /* scroll wheel handling */
207 if (GPIOA_MIS & SCROLLWHEEL_BITS)
208 scrollwheel(GPIOA_PIN76 >> 6);
209
210 /* ack interrupt */
211 GPIOA_IC = SCROLLWHEEL_BITS;
50#endif 212#endif
51} 213}
52 214
215
53/* 216/*
54 * Get button pressed from hardware 217 * Get button pressed from hardware
55 */ 218 */
56
57
58int button_read_device(void) 219int button_read_device(void)
59{ 220{
60 int btn = 0; 221 int btn = 0;
@@ -62,12 +223,12 @@ int button_read_device(void)
62 static long power_counter = 0; 223 static long power_counter = 0;
63 unsigned gpiod6; 224 unsigned gpiod6;
64 225
65
66 /* if we don't wait for the fifo to empty, we'll see screen corruption 226 /* if we don't wait for the fifo to empty, we'll see screen corruption
67 * (the higher the CPU frequency the higher the corruption) */ 227 * (the higher the CPU frequency the higher the corruption) */
68 while ((DBOP_STAT & (1<<10)) == 0); 228 while ((DBOP_STAT & (1<<10)) == 0);
69 229
70 get_scrollwheel(); 230 int delay = 30;
231 while(delay--) nop;
71 232
72 CCU_IO &= ~(1<<12); 233 CCU_IO &= ~(1<<12);
73 234
@@ -77,6 +238,7 @@ int button_read_device(void)
77 gpiod6 = GPIOD_PIN(6); 238 gpiod6 = GPIOD_PIN(6);
78 239
79 GPIOB_PIN(0) = 0; 240 GPIOB_PIN(0) = 0;
241
80 udelay(1); 242 udelay(1);
81 243
82 if (GPIOC_PIN(1) & 1<<1) 244 if (GPIOC_PIN(1) & 1<<1)
@@ -114,6 +276,12 @@ int button_read_device(void)
114 { 276 {
115 hold_button_old = hold_button; 277 hold_button_old = hold_button;
116 backlight_hold_changed(hold_button); 278 backlight_hold_changed(hold_button);
279 /* mask scrollwheel irq so we don't need to check for
280 * the hold button in the isr */
281 if (hold_button)
282 GPIOA_IE &= ~SCROLLWHEEL_BITS;
283 else
284 GPIOA_IE |= SCROLLWHEEL_BITS;
117 } 285 }
118#else 286#else
119 (void)hold_button_old; 287 (void)hold_button_old;