summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/sansa-fuze/button-fuze.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/as3525/sansa-fuze/button-fuze.c')
-rw-r--r--firmware/target/arm/as3525/sansa-fuze/button-fuze.c257
1 files changed, 184 insertions, 73 deletions
diff --git a/firmware/target/arm/as3525/sansa-fuze/button-fuze.c b/firmware/target/arm/as3525/sansa-fuze/button-fuze.c
index 36a0f3aeda..2414900727 100644
--- a/firmware/target/arm/as3525/sansa-fuze/button-fuze.c
+++ b/firmware/target/arm/as3525/sansa-fuze/button-fuze.c
@@ -7,7 +7,8 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2006 by Barry Wardell 10 * Copyright (C) 2008 by Thomas Martitz
11 * Copyright (C) 2008 by Dominik Wenger
11 * 12 *
12 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 14 * modify it under the terms of the GNU General Public License
@@ -19,118 +20,229 @@
19 * 20 *
20 ****************************************************************************/ 21 ****************************************************************************/
21 22
22/* Taken from button-h10.c by Barry Wardell and reverse engineering by MrH. */ 23
24/* Basic button driver for the Fuze
25 *
26 * TODO: - Get the wheel working with interrupts
27 * - find that Home button
28 */
23 29
24#include "system.h" 30#include "system.h"
25#include "button.h" 31#include "button.h"
32#include "button-target.h"
26#include "backlight.h" 33#include "backlight.h"
27#include "powermgmt.h"
28 34
29#define WHEEL_REPEAT_INTERVAL 300000 35#define WHEEL_REPEAT_INTERVAL 30
30#define WHEEL_FAST_ON_INTERVAL 20000
31#define WHEEL_FAST_OFF_INTERVAL 60000
32#define WHEELCLICKS_PER_ROTATION 48 /* wheelclicks per full rotation */ 36#define WHEELCLICKS_PER_ROTATION 48 /* wheelclicks per full rotation */
33 37
34/* Clickwheel */
35#ifndef BOOTLOADER 38#ifndef BOOTLOADER
36static unsigned int old_wheel_value = 0;
37static unsigned int wheel_repeat = BUTTON_NONE;
38static unsigned int wheel_click_count = 0;
39static unsigned int wheel_delta = 0;
40static int wheel_fast_mode = 0;
41static unsigned long last_wheel_usec = 0;
42static unsigned long wheel_velocity = 0;
43static long last_wheel_post = 0;
44static long next_backlight_on = 0;
45/* Buttons */ 39/* Buttons */
46static bool hold_button = false; 40static bool hold_button = false;
47static bool hold_button_old = false; 41static bool hold_button_old = false;
48#define _button_hold() hold_button
49#else 42#else
50#define _button_hold() false /* FIXME */ 43#define hold_button false
51#endif /* BOOTLOADER */ 44#endif /* !BOOTLOADER */
52static int int_btn = BUTTON_NONE; 45static int int_btn = BUTTON_NONE;
46static short dbop_din = BUTTON_NONE;
53 47
54void button_init_device(void) 48void button_init_device(void)
55{ 49{
50 GPIOA_DIR |= (1<<1);
51 GPIOA_PIN(1) = (1<<1);
52}
53
54/* clickwheel */
55#if !defined(BOOTLOADER) && defined(HAVE_SCROLLWHEEL)
56static void get_wheel(void)
57{
58 static unsigned int old_wheel_value = 0;
59 static unsigned int wheel_value = 0;
60 static unsigned int wheel_repeat = BUTTON_NONE;
61 /* getting BUTTON_REPEAT works like this: We increment repeat by if the
62 * wheel was turned, and decrement it by 1 each tick,
63 * that means: if you change the wheel fast enough, repeat will be >1 and
64 * we send BUTTON_REPEAT
65 */
66 static int repeat;
67 /* we omit 3 of 4 posts to the button_queue, that works better, so count */
68 static int counter = 0;
69 /* Read wheel
70 * Bits 13 and 14 of DBOP_DIN change as follows:
71 * Clockwise rotation 00 -> 01 -> 11 -> 10 -> 00
72 * Counter-clockwise 00 -> 10 -> 11 -> 01 -> 00
73 */
74 static const unsigned char wheel_tbl[2][4] =
75 {
76 { 2, 0, 3, 1 }, /* Clockwise rotation */
77 { 1, 3, 0, 2 }, /* Counter-clockwise */
78 };
79 wheel_value = dbop_din & (1<<13|1<<14);
80 wheel_value >>= 13;
81 /* did the wheel value change? */
82 if (!hold_button)
83 {
84 unsigned int btn = BUTTON_NONE;
85 if (old_wheel_value == wheel_tbl[0][wheel_value])
86 btn = BUTTON_SCROLL_FWD;
87 else if (old_wheel_value == wheel_tbl[1][wheel_value])
88 btn = BUTTON_SCROLL_BACK;
89
90 if (btn != BUTTON_NONE)
91 {
92 if (btn != wheel_repeat)
93 {
94 /* direction reversals nullify repeats */
95 wheel_repeat = btn;
96 repeat = 0;
97 }
98 if (btn != BUTTON_NONE)
99 {
100 /* generate repeats if quick enough */
101 if (repeat > 0)
102 {
103 btn |= BUTTON_REPEAT;
104 }
105 repeat += 2;
106 /* the wheel is more reliable if we don't send ever change,
107 * every 4th is basically one "physical click" is 1 item in
108 * the rockbox menus */
109 if (queue_empty(&button_queue) && ++counter >= 4)
110 {
111 backlight_on();
112 /* 1<<24 is rather arbitary, seems to work well */
113 queue_post(&button_queue, btn, 1<<24);
114 /* message posted - reset count */
115 counter = 0;
116 }
117 }
118 }
119 }
120 if (repeat > 0)
121 repeat--;
122 else
123 repeat = 0;
124 old_wheel_value = wheel_value;
125}
126#endif /* !defined(BOOTLOADER) && defined(SCROLLWHEEL) */
127
128#if !defined(BOOTLOADER)
129/* get hold button state */
130static void get_hold(void)
131{
132 hold_button = dbop_din & (1<<12);
56} 133}
134#endif
57 135
58bool button_hold(void) 136bool button_hold(void)
59{ 137{
60 return _button_hold(); 138 return hold_button;
61} 139}
62 140
63/* clickwheel */ 141static void get_power(void)
64#ifndef BOOTLOADER
65void clickwheel_int(void)
66{ 142{
143 if (dbop_din & (1<<8))
144 int_btn |= BUTTON_POWER;
67} 145}
68#endif /* BOOTLOADER */
69 146
70/* device buttons */ 147static void get_button_from_dbob(void)
148{
149 int_btn &= ~(BUTTON_HOLD|
150 BUTTON_POWER);
151
152 /* Wait for fifo to empty */
153 while ((DBOP_STAT & (1<<10)) == 0);
154
155 DBOP_CTRL |= (1<<19);
156 DBOP_CTRL &= ~(1<<16); /* disable output */
157
158 DBOP_TIMPOL_01 = 0xe167e167;
159 DBOP_TIMPOL_23 = 0xe167006e;
160 int loop = 0;
161 do
162 {
163 asm volatile ("nop\n");
164 loop++;
165 } while(loop < 64);
166
167 DBOP_CTRL |= (1<<15); /* start read */
168 int temp;
169 do
170 {
171 temp = DBOP_STAT;
172 } while ((temp & (1<<16)) == 0); /* wait for valid data */
173
174 dbop_din = DBOP_DIN; /* now read */
175
176 DBOP_TIMPOL_01 = 0x6e167;
177 DBOP_TIMPOL_23 = 0xa167e06f;
178
179 DBOP_CTRL |= (1<<16);
180 DBOP_CTRL &= ~(1<<19);
71 181
72/* device buttons */ 182#if !defined(BOOTLOADER)
73void button_int(void) 183 get_hold();
184#if defined(HAVE_SCROLLWHEEL)
185 get_wheel();
186#endif
187#endif
188 get_power();
189}
190
191static void get_button_from_gpio(void)
74{ 192{
75 int dir_save_b = 0; 193 /* reset buttons we're going to read */
76 int afsel_save_b = 0; 194 int_btn &= ~(BUTTON_LEFT|
77 int dir_save_c = 0; 195 BUTTON_RIGHT|
78 int afsel_save_c = 0; 196 BUTTON_UP|
79 197 BUTTON_DOWN|
80 int_btn = BUTTON_NONE; 198 BUTTON_SELECT);
81 199 if(hold_button)
82 /* Save the current direction and afsel */ 200 return;
83 dir_save_b = GPIOB_DIR; 201 /* set afsel, so that we can read our buttons */
84 afsel_save_b = GPIOB_AFSEL; 202 GPIOC_AFSEL &= ~(1<<2|1<<3|1<<4|1<<5|1<<6);
85 dir_save_c = GPIOC_DIR; 203 /* set dir so we can read our buttons (but reset the C pins first) */
86 afsel_save_c = GPIOC_AFSEL; 204 GPIOB_DIR &= ~(1<<4);
87 205 GPIOC_DIR |= (1<<2|1<<3|1<<4|1<<5|1<<6);
88 GPIOB_DIR = 0; 206 GPIOC_PIN(2) |= (1<<2);
89 GPIOB_AFSEL = 0; 207 GPIOC_PIN(3) |= (1<<3);
90 GPIOC_DIR = 0; 208 GPIOC_PIN(4) |= (1<<4);
91 GPIOC_AFSEL = 0; 209 GPIOC_PIN(5) |= (1<<5);
92 210 GPIOC_PIN(6) |= (1<<6);
93 /* These should not be needed with button event interupts */ 211
94 /* they are necessary now to clear out lcd data */ 212 GPIOC_DIR &= ~(1<<2|1<<3|1<<4|1<<5|1<<6);
95 GPIOC_PIN(0) |= 1; 213
96 GPIOC_PIN(1) |= 1; 214 /* small delay needed to read buttons correctly */
97 GPIOC_PIN(2) |= 1; 215 int delay = 50;
98 GPIOC_PIN(3) |= 1; 216 while(delay >0) delay--;
99 GPIOC_PIN(4) |= 1;
100 GPIOC_PIN(5) |= 1;
101 GPIOC_PIN(6) |= 1;
102 GPIOC_PIN(7) |= 1;
103 217
104 /* direct GPIO connections */ 218 /* direct GPIO connections */
105 if (GPIOB_PIN(4)) 219 if (!GPIOC_PIN(3))
106 int_btn |= BUTTON_POWER; 220 int_btn |= BUTTON_LEFT;
221 if (!GPIOC_PIN(2))
222 int_btn |= BUTTON_UP;
107 if (!GPIOC_PIN(6)) 223 if (!GPIOC_PIN(6))
108 int_btn |= BUTTON_DOWN; 224 int_btn |= BUTTON_DOWN;
109 if (!GPIOC_PIN(5)) 225 if (!GPIOC_PIN(5))
110 int_btn |= BUTTON_RIGHT; 226 int_btn |= BUTTON_RIGHT;
111 if (!GPIOC_PIN(4)) 227 if (!GPIOC_PIN(4))
112 int_btn |= BUTTON_SELECT; 228 int_btn |= BUTTON_SELECT;
113 if (!GPIOC_PIN(3))
114 int_btn |= BUTTON_LEFT;
115 if (!GPIOC_PIN(2))
116 int_btn |= BUTTON_UP;
117
118 /* return to settings needed for lcd */ 229 /* return to settings needed for lcd */
119 GPIOB_DIR = dir_save_b; 230 GPIOC_DIR |= (1<<2|1<<3|1<<4|1<<5|1<<6);
120 GPIOB_AFSEL = afsel_save_b; 231 GPIOC_AFSEL |= (1<<2|1<<3|1<<4|1<<5|1<<6);
121 GPIOC_DIR = dir_save_c;
122 GPIOC_AFSEL = afsel_save_c;
123} 232}
124 233
234static inline void get_buttons_from_hw(void)
235{
236 get_button_from_dbob();
237 get_button_from_gpio();
238}
125/* 239/*
126 * Get button pressed from hardware 240 * Get button pressed from hardware
127 */ 241 */
128int button_read_device(void) 242int button_read_device(void)
129{ 243{
130#ifdef BOOTLOADER 244 get_buttons_from_hw();
131 /* Read buttons directly in the bootloader */ 245#ifndef BOOTLOADER
132 button_int();
133#else
134 /* light handling */ 246 /* light handling */
135 if (hold_button != hold_button_old) 247 if (hold_button != hold_button_old)
136 { 248 {
@@ -139,6 +251,5 @@ int button_read_device(void)
139 } 251 }
140#endif /* BOOTLOADER */ 252#endif /* BOOTLOADER */
141 253
142 /* The int_btn variable is set in the button interrupt handler */ 254 return int_btn; /* set in button_int */
143 return int_btn;
144} 255}