summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/keymaps/keymap-gigabeat-s.c64
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/export/config-gigabeat-s.h2
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/button-imx31.c31
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/button-target.h14
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c201
6 files changed, 290 insertions, 23 deletions
diff --git a/apps/keymaps/keymap-gigabeat-s.c b/apps/keymaps/keymap-gigabeat-s.c
index 32c4f22b5b..d32177ea90 100644
--- a/apps/keymaps/keymap-gigabeat-s.c
+++ b/apps/keymaps/keymap-gigabeat-s.c
@@ -309,8 +309,72 @@ static const struct button_mapping button_context_radio[] = {
309 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS) 309 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
310}; 310};
311 311
312/*****************************************************************************
313 * Remote control mappings
314 *****************************************************************************/
315static const struct button_mapping remote_button_context_standard[] = {
316 { ACTION_STD_PREV, BUTTON_RC_VOL_UP, BUTTON_NONE },
317 { ACTION_STD_PREVREPEAT, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
318 { ACTION_STD_NEXT, BUTTON_RC_VOL_DOWN, BUTTON_NONE },
319 { ACTION_STD_NEXTREPEAT, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
320 { ACTION_STD_CANCEL, BUTTON_RC_REW, BUTTON_NONE },
321 { ACTION_STD_OK, BUTTON_RC_FF|BUTTON_REL, BUTTON_RC_FF },
322 { ACTION_STD_CONTEXT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_RC_FF },
323 { ACTION_STD_MENU, BUTTON_RC_DSP, BUTTON_NONE },
324
325 LAST_ITEM_IN_LIST
326};
327
328static const struct button_mapping remote_button_context_wps[] = {
329 { ACTION_WPS_PLAY, BUTTON_RC_PLAY, BUTTON_NONE },
330
331 { ACTION_WPS_SKIPNEXT, BUTTON_RC_FF|BUTTON_REL, BUTTON_RC_FF },
332 { ACTION_WPS_SKIPPREV, BUTTON_RC_REW|BUTTON_REL, BUTTON_RC_REW },
333
334 { ACTION_WPS_SEEKBACK, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE },
335 { ACTION_WPS_SEEKFWD, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE },
336 { ACTION_WPS_STOPSEEK, BUTTON_RC_REW|BUTTON_REL, BUTTON_RC_REW|BUTTON_REPEAT },
337 { ACTION_WPS_STOPSEEK, BUTTON_RC_FF|BUTTON_REL, BUTTON_RC_FF|BUTTON_REPEAT },
338
339 { ACTION_WPS_STOP, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_RC_PLAY },
340 { ACTION_WPS_MENU, BUTTON_RC_DSP, BUTTON_NONE },
341
342 { ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN, BUTTON_NONE },
343 { ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
344 { ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
345 { ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP, BUTTON_NONE },
346
347 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
348};
349
350static const struct button_mapping remote_button_context_tree[] = {
351 { ACTION_TREE_WPS, BUTTON_RC_PLAY|BUTTON_REL, BUTTON_RC_PLAY },
352 { ACTION_TREE_STOP, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_RC_PLAY },
353 { ACTION_STD_CANCEL, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE },
354
355 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
356};
357
358static const struct button_mapping* get_context_mapping_remote( int context )
359{
360 context ^= CONTEXT_REMOTE;
361
362 switch (context)
363 {
364 case CONTEXT_WPS:
365 return remote_button_context_wps;
366 case CONTEXT_MAINMENU:
367 case CONTEXT_TREE:
368 return remote_button_context_tree;
369 }
370 return remote_button_context_standard;
371}
372
312const struct button_mapping* get_context_mapping(int context) 373const struct button_mapping* get_context_mapping(int context)
313{ 374{
375 if (context&CONTEXT_REMOTE)
376 return get_context_mapping_remote(context);
377
314 switch (context) 378 switch (context)
315 { 379 {
316 case CONTEXT_STD: 380 case CONTEXT_STD:
diff --git a/firmware/SOURCES b/firmware/SOURCES
index bce384e1c8..c8c38ceee2 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -774,6 +774,7 @@ target/arm/imx31/gigabeat-s/wmcodec-imx31.c
774#ifndef BOOTLOADER 774#ifndef BOOTLOADER
775target/arm/imx31/gigabeat-s/audio-gigabeat-s.c 775target/arm/imx31/gigabeat-s/audio-gigabeat-s.c
776target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c 776target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
777target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c
777target/arm/imx31/gigabeat-s/pcm-imx31.c 778target/arm/imx31/gigabeat-s/pcm-imx31.c
778target/arm/imx31/gigabeat-s/timer-imx31.c 779target/arm/imx31/gigabeat-s/timer-imx31.c
779#endif 780#endif
diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h
index 9e6029f00b..93068ae441 100644
--- a/firmware/export/config-gigabeat-s.h
+++ b/firmware/export/config-gigabeat-s.h
@@ -140,7 +140,7 @@
140#define GPIO_EVENT_MASK (USE_GPIO1_EVENTS) 140#define GPIO_EVENT_MASK (USE_GPIO1_EVENTS)
141 141
142/* Define this if target has an additional number of threads specific to it */ 142/* Define this if target has an additional number of threads specific to it */
143#define TARGET_EXTRA_THREADS 1 143#define TARGET_EXTRA_THREADS 2
144 144
145/* Type of mobile power - check this out */ 145/* Type of mobile power - check this out */
146#define BATTERY_CAPACITY_DEFAULT 700 /* default battery capacity */ 146#define BATTERY_CAPACITY_DEFAULT 700 /* default battery capacity */
diff --git a/firmware/target/arm/imx31/gigabeat-s/button-imx31.c b/firmware/target/arm/imx31/gigabeat-s/button-imx31.c
index 587e66e0bc..dec0aa108f 100644
--- a/firmware/target/arm/imx31/gigabeat-s/button-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/button-imx31.c
@@ -32,9 +32,6 @@
32 32
33/* Most code in here is taken from the Linux BSP provided by Freescale 33/* Most code in here is taken from the Linux BSP provided by Freescale
34 * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. */ 34 * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. */
35#ifdef HAVE_HEADPHONE_DETECTION
36static bool headphones_detect = false;
37#endif
38static uint32_t int_btn = BUTTON_NONE; 35static uint32_t int_btn = BUTTON_NONE;
39static bool hold_button = false; 36static bool hold_button = false;
40#ifdef BOOTLOADER 37#ifdef BOOTLOADER
@@ -123,6 +120,16 @@ bool button_hold(void)
123 return _button_hold(); 120 return _button_hold();
124} 121}
125 122
123#ifdef HAVE_HEADPHONE_DETECTION
124/* Headphone driver pushes the data here */
125void button_headphone_set(int button)
126{
127 int oldstatus = disable_irq_save();
128 int_btn = (int_btn & ~BUTTON_REMOTE) | button;
129 restore_irq(oldstatus);
130}
131#endif
132
126int button_read_device(void) 133int button_read_device(void)
127{ 134{
128 /* Simple poll of GPIO status */ 135 /* Simple poll of GPIO status */
@@ -168,21 +175,6 @@ void button_power_event(void)
168 restore_irq(oldlevel); 175 restore_irq(oldlevel);
169} 176}
170 177
171#ifdef HAVE_HEADPHONE_DETECTION
172/* This is called from the mc13783 interrupt thread */
173void headphone_detect_event(void)
174{
175 /* FIXME: Not really the correct method */
176 headphones_detect =
177 (mc13783_read(MC13783_INTERRUPT_SENSE1) & MC13783_ONOFD2S) == 0;
178}
179
180bool headphones_inserted(void)
181{
182 return headphones_detect;
183}
184#endif /* HAVE_HEADPHONE_DETECTION */
185
186void button_init_device(void) 178void button_init_device(void)
187{ 179{
188#ifdef BOOTLOADER 180#ifdef BOOTLOADER
@@ -223,8 +215,7 @@ void button_init_device(void)
223 mc13783_enable_event(MC13783_ONOFD1_EVENT); 215 mc13783_enable_event(MC13783_ONOFD1_EVENT);
224 216
225#ifdef HAVE_HEADPHONE_DETECTION 217#ifdef HAVE_HEADPHONE_DETECTION
226 headphone_detect_event(); 218 headphone_init();
227 mc13783_enable_event(MC13783_ONOFD2_EVENT);
228#endif 219#endif
229} 220}
230 221
diff --git a/firmware/target/arm/imx31/gigabeat-s/button-target.h b/firmware/target/arm/imx31/gigabeat-s/button-target.h
index 754694eee5..d970e9983c 100644
--- a/firmware/target/arm/imx31/gigabeat-s/button-target.h
+++ b/firmware/target/arm/imx31/gigabeat-s/button-target.h
@@ -37,6 +37,8 @@ int button_read_device(void);
37void button_power_event(void); 37void button_power_event(void);
38void headphone_detect_event(void); 38void headphone_detect_event(void);
39bool headphones_inserted(void); 39bool headphones_inserted(void);
40void headphone_init(void);
41void button_headphone_set(int button);
40 42
41/* Toshiba Gigabeat S-specific button codes */ 43/* Toshiba Gigabeat S-specific button codes */
42 44
@@ -55,9 +57,17 @@ bool headphones_inserted(void);
55#define BUTTON_NEXT (1 << 11) 57#define BUTTON_NEXT (1 << 11)
56#define BUTTON_POWER (1 << 12) /* Read from PMIC */ 58#define BUTTON_POWER (1 << 12) /* Read from PMIC */
57 59
58#define BUTTON_MAIN (0x1fff) 60#define BUTTON_MAIN (0x00001fff)
59 61
60#define BUTTON_REMOTE 0 62/* Remote control buttons */
63#define BUTTON_RC_VOL_UP (1 << 13)
64#define BUTTON_RC_VOL_DOWN (1 << 14)
65#define BUTTON_RC_FF (1 << 15)
66#define BUTTON_RC_REW (1 << 16)
67#define BUTTON_RC_PLAY (1 << 17)
68#define BUTTON_RC_DSP (1 << 18)
69
70#define BUTTON_REMOTE (0x0007e000)
61 71
62#define POWEROFF_BUTTON BUTTON_POWER 72#define POWEROFF_BUTTON BUTTON_POWER
63#define POWEROFF_COUNT 10 73#define POWEROFF_COUNT 10
diff --git a/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c
new file mode 100644
index 0000000000..6043d00bf5
--- /dev/null
+++ b/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c
@@ -0,0 +1,201 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2009 by Michael Sevakis
11 *
12 * Driver to handle headphone jack events
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include "config.h"
24#include "system.h"
25#include "kernel.h"
26#include "thread.h"
27#include "mc13783.h"
28#include "mc13783-target.h"
29#include "adc.h"
30#include "button.h"
31
32static struct wakeup headphone_wakeup;
33static unsigned int headphone_thread_id;
34static int headphone_stack[160/sizeof(int)]; /* Not much stack needed */
35static const char * const headphone_thread_name = "headphone";
36static bool headphones_detect = false;
37
38/* Convert ADC reading into a button value. */
39static int adc_data_to_button(unsigned int data)
40{
41 int btn = BUTTON_NONE;
42
43 if (data < 505)
44 {
45 if (data < 252)
46 {
47 if (data < 149)
48 {
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 {
78 if (data < 870)
79 {
80 if (data < 675)
81 {
82 /* Vol + */
83 btn = BUTTON_RC_VOL_UP;
84 }
85 else
86 {
87 /* Vol - */
88 btn = BUTTON_RC_VOL_DOWN;
89 }
90 }
91#if 0
92 else
93 {
94
95 if (data < 951)
96 {
97 /* No buttons */
98 }
99 else
100 {
101 /* Not inserted */
102
103 }
104 }
105#endif
106 }
107
108 return btn;
109}
110
111static void headphone_thread(void)
112{
113 int headphone_sleep_countdown = 0;
114 int headphone_wait_timeout = TIMEOUT_BLOCK;
115
116 while (1)
117 {
118 int rc = wakeup_wait(&headphone_wakeup, headphone_wait_timeout);
119 unsigned int data = adc_read(ADC_HPREMOTE);
120
121 if (rc == OBJ_WAIT_TIMEDOUT)
122 {
123 if (headphone_sleep_countdown <= 0)
124 {
125 /* Polling ADC */
126 int btn, btn2;
127
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 {
135 /* If the buttons dont agree twice in a row, then it's
136 * none (from meg-fx remote reader). */
137 btn = BUTTON_NONE;
138 }
139
140 button_headphone_set(btn);
141 continue;
142 }
143
144 if (--headphone_sleep_countdown == 0)
145 {
146 /* Nothing has changed and remote is not present -
147 * go to sleep. */
148 headphone_wait_timeout = TIMEOUT_BLOCK;
149 continue;
150 }
151 }
152
153 headphones_detect = data <= 951; /* Max remote value */
154
155 /* Cancel any buttons if jack readings are unstable. */
156 button_headphone_set(BUTTON_NONE);
157
158 if (data >= 64 && data <= 951)
159 {
160 /* Should be a remote control - accelerate */
161 headphone_wait_timeout = HZ/20-HZ/50;
162 headphone_sleep_countdown = 0;
163 }
164 else if (rc == OBJ_WAIT_SUCCEEDED)
165 {
166 /* Got signaled - something is being plugged/unplugged. Set
167 * countdown until we just give up and go to sleep (~10s). */
168 headphone_wait_timeout = HZ/2;
169 headphone_sleep_countdown = 10*2;
170 }
171 }
172}
173
174/* This is called from the mc13783 interrupt thread */
175void headphone_detect_event(void)
176{
177 /* Trigger the thread immediately. */
178 wakeup_signal(&headphone_wakeup);
179}
180
181/* Tell if anything is in the jack. */
182bool headphones_inserted(void)
183{
184 return headphones_detect;
185}
186
187void headphone_init(void)
188{
189 /* A thread is required to monitor the remote ADC and jack state. */
190 wakeup_init(&headphone_wakeup);
191 headphone_thread_id = create_thread(headphone_thread,
192 headphone_stack,
193 sizeof(headphone_stack),
194 0, headphone_thread_name
195 IF_PRIO(, PRIORITY_REALTIME)
196 IF_COP(, CPU));
197
198 /* Initially poll and then enable PMIC event */
199 headphone_detect_event();
200 mc13783_enable_event(MC13783_ONOFD2_EVENT);
201}