diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c | 135 |
1 files changed, 54 insertions, 81 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c index 4e1792d467..6fdde32185 100644 --- a/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c | |||
@@ -31,87 +31,65 @@ | |||
31 | 31 | ||
32 | static struct semaphore headphone_wakeup; | 32 | static struct semaphore headphone_wakeup; |
33 | static unsigned int headphone_thread_id; | 33 | static unsigned int headphone_thread_id; |
34 | static int headphone_stack[200/sizeof(int)]; /* Not much stack needed */ | 34 | static unsigned int headphone_stack[176/sizeof(int)]; /* Little stack needed */ |
35 | static const char * const headphone_thread_name = "headphone"; | 35 | static const char * const headphone_thread_name = "headphone"; |
36 | static bool headphones_detect = false; | 36 | static bool headphones_detect = false; |
37 | 37 | ||
38 | /* Convert ADC reading into a button value. */ | 38 | /* Convert ADC reading into a button value. */ |
39 | static int adc_data_to_button(unsigned int data) | 39 | static int adc_data_to_button(unsigned int data) |
40 | { | 40 | { |
41 | int btn = BUTTON_NONE; | 41 | /* _______370_______ |
42 | 42 | * ___149___ ___675___ | |
43 | if (data < 505) | 43 | * ___64__ __252__ __505__ __870__ |
44 | { | 44 | * x PLAY DSP REW FF VOL+ VOL- x |
45 | if (data < 252) | 45 | * |
46 | { | 46 | * Child nodes are at 2*n and 2*n+1 per usual bintree array representation |
47 | if (data < 149) | 47 | */ |
48 | { | 48 | static const unsigned int button_tree[16] = |
49 | if (data >= 64) | ||
50 | { | ||
51 | /* Play/Pause */ | ||
52 | btn = BUTTON_RC_PLAY; | ||
53 | } | ||
54 | /* else headphone direct */ | ||
55 | } | ||
56 | else | ||
57 | { | ||
58 | /* DSP */ | ||
59 | btn = BUTTON_RC_DSP; | ||
60 | } | ||
61 | } | ||
62 | else | ||
63 | { | ||
64 | if (data < 370) | ||
65 | { | ||
66 | /* RW */ | ||
67 | btn = BUTTON_RC_REW; | ||
68 | } | ||
69 | else | ||
70 | { | ||
71 | /* FF */ | ||
72 | btn = BUTTON_RC_FF; | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | else | ||
77 | { | 49 | { |
78 | if (data < 870) | 50 | [ 0] = 0, |
79 | { | 51 | [ 1] = 370, |
80 | if (data < 675) | 52 | [ 2] = 149, |
81 | { | 53 | [ 3] = 675, |
82 | /* Vol + */ | 54 | [ 4] = 64, |
83 | btn = BUTTON_RC_VOL_UP; | 55 | [ 5] = 252, |
84 | } | 56 | [ 6] = 505, |
85 | else | 57 | [ 7] = 870, |
86 | { | 58 | [ 8] = BUTTON_NONE, |
87 | /* Vol - */ | 59 | [ 9] = BUTTON_RC_PLAY, |
88 | btn = BUTTON_RC_VOL_DOWN; | 60 | [10] = BUTTON_RC_DSP, |
89 | } | 61 | [11] = BUTTON_RC_REW, |
90 | } | 62 | [12] = BUTTON_RC_FF, |
91 | #if 0 | 63 | [13] = BUTTON_RC_VOL_UP, |
92 | else | 64 | [14] = BUTTON_RC_VOL_DOWN, |
93 | { | 65 | [15] = BUTTON_NONE, |
94 | 66 | }; | |
95 | if (data < 951) | 67 | |
96 | { | 68 | int i, button; |
97 | /* No buttons */ | 69 | |
98 | } | 70 | asm volatile ( |
99 | else | 71 | "ldr %0, [%2, #1*4] \n" /* button = button_tree[1] */ |
100 | { | 72 | "mov %1, #1 \n" /* i = 1 */ |
101 | /* Not inserted */ | 73 | "cmp %3, %0 \n" /* C=1 if data > button */ |
102 | 74 | "adc %1, %1, %1 \n" /* i = 2*n + C */ | |
103 | } | 75 | "ldr %0, [%2, %1, lsl #2] \n" /* button = button_tree[i] */ |
104 | } | 76 | "cmp %3, %0 \n" /* C=1 if data > button */ |
105 | #endif | 77 | "adc %1, %1, %1 \n" /* i = 2*n + C */ |
106 | } | 78 | "ldr %0, [%2, %1, lsl #2] \n" /* button = button_tree[i] */ |
107 | 79 | "cmp %3, %0 \n" /* C=1 if data > button */ | |
108 | return btn; | 80 | "adc %1, %1, %1 \n" /* i = 2*n + C */ |
81 | "ldr %0, [%2, %1, lsl #2] \n" /* button = button_tree[i] */ | ||
82 | : "=&r"(button), "=&r"(i) | ||
83 | : "r"(button_tree), "r"(data)); | ||
84 | |||
85 | return button; | ||
109 | } | 86 | } |
110 | 87 | ||
111 | static void headphone_thread(void) | 88 | static void NORETURN_ATTR headphone_thread(void) |
112 | { | 89 | { |
113 | int headphone_sleep_countdown = 0; | 90 | int headphone_sleep_countdown = 0; |
114 | int headphone_wait_timeout = TIMEOUT_BLOCK; | 91 | int headphone_wait_timeout = TIMEOUT_BLOCK; |
92 | int last_btn = BUTTON_NONE; | ||
115 | 93 | ||
116 | while (1) | 94 | while (1) |
117 | { | 95 | { |
@@ -123,15 +101,10 @@ static void headphone_thread(void) | |||
123 | if (headphone_sleep_countdown <= 0) | 101 | if (headphone_sleep_countdown <= 0) |
124 | { | 102 | { |
125 | /* Polling ADC */ | 103 | /* Polling ADC */ |
126 | int btn, btn2; | 104 | int btn = adc_data_to_button(data); |
127 | 105 | if (btn != last_btn) | |
128 | btn = adc_data_to_button(data); | ||
129 | sleep(HZ/50); | ||
130 | data = adc_read(ADC_HPREMOTE); | ||
131 | btn2 = adc_data_to_button(data); | ||
132 | |||
133 | if (btn != btn2) | ||
134 | { | 106 | { |
107 | last_btn = btn; | ||
135 | /* If the buttons dont agree twice in a row, then it's | 108 | /* If the buttons dont agree twice in a row, then it's |
136 | * none (from meg-fx remote reader). */ | 109 | * none (from meg-fx remote reader). */ |
137 | btn = BUTTON_NONE; | 110 | btn = BUTTON_NONE; |
@@ -154,11 +127,12 @@ static void headphone_thread(void) | |||
154 | 127 | ||
155 | /* Cancel any buttons if jack readings are unstable. */ | 128 | /* Cancel any buttons if jack readings are unstable. */ |
156 | button_headphone_set(BUTTON_NONE); | 129 | button_headphone_set(BUTTON_NONE); |
130 | last_btn = BUTTON_NONE; | ||
157 | 131 | ||
158 | if (data >= 64 && data <= 951) | 132 | if (data >= 64 && data <= 951) |
159 | { | 133 | { |
160 | /* Should be a remote control - accelerate */ | 134 | /* Should be a remote control - accelerate */ |
161 | headphone_wait_timeout = HZ/20-HZ/50; | 135 | headphone_wait_timeout = HZ/25; |
162 | headphone_sleep_countdown = 0; | 136 | headphone_sleep_countdown = 0; |
163 | } | 137 | } |
164 | else if (rc == OBJ_WAIT_SUCCEEDED) | 138 | else if (rc == OBJ_WAIT_SUCCEEDED) |
@@ -187,7 +161,7 @@ bool headphones_inserted(void) | |||
187 | void INIT_ATTR headphone_init(void) | 161 | void INIT_ATTR headphone_init(void) |
188 | { | 162 | { |
189 | /* A thread is required to monitor the remote ADC and jack state. */ | 163 | /* A thread is required to monitor the remote ADC and jack state. */ |
190 | semaphore_init(&headphone_wakeup, 1, 0); | 164 | semaphore_init(&headphone_wakeup, 1, 1); |
191 | headphone_thread_id = create_thread(headphone_thread, | 165 | headphone_thread_id = create_thread(headphone_thread, |
192 | headphone_stack, | 166 | headphone_stack, |
193 | sizeof(headphone_stack), | 167 | sizeof(headphone_stack), |
@@ -195,7 +169,6 @@ void INIT_ATTR headphone_init(void) | |||
195 | IF_PRIO(, PRIORITY_REALTIME) | 169 | IF_PRIO(, PRIORITY_REALTIME) |
196 | IF_COP(, CPU)); | 170 | IF_COP(, CPU)); |
197 | 171 | ||
198 | /* Initially poll and then enable PMIC event */ | 172 | /* Enable PMIC event */ |
199 | headphone_detect_event(); | ||
200 | mc13783_enable_event(MC13783_ONOFD2_EVENT, true); | 173 | mc13783_enable_event(MC13783_ONOFD2_EVENT, true); |
201 | } | 174 | } |