diff options
-rw-r--r-- | apps/keymaps/keymap-e200.c | 20 | ||||
-rw-r--r-- | apps/settings_list.c | 6 | ||||
-rw-r--r-- | firmware/SOURCES | 5 | ||||
-rw-r--r-- | firmware/drivers/audio/as3514.c | 309 | ||||
-rw-r--r-- | firmware/export/audio.h | 3 | ||||
-rw-r--r-- | firmware/export/audiohw.h | 3 | ||||
-rw-r--r-- | firmware/export/config-e200.h | 15 | ||||
-rw-r--r-- | firmware/export/pcm_sampr.h | 15 | ||||
-rw-r--r-- | firmware/sound.c | 2 | ||||
-rw-r--r-- | firmware/target/arm/pcm-pp.c | 202 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/ata-e200.c | 11 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/audio-e200.c | 103 |
12 files changed, 560 insertions, 134 deletions
diff --git a/apps/keymaps/keymap-e200.c b/apps/keymaps/keymap-e200.c index 783d86f476..55e30ca258 100644 --- a/apps/keymaps/keymap-e200.c +++ b/apps/keymaps/keymap-e200.c | |||
@@ -201,6 +201,24 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
201 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 201 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
202 | }; /* button_context_pitchscreen */ | 202 | }; /* button_context_pitchscreen */ |
203 | 203 | ||
204 | /** Recording Screen **/ | ||
205 | static const struct button_mapping button_context_recscreen[] = { | ||
206 | { ACTION_REC_PAUSE, BUTTON_UP|BUTTON_REL, BUTTON_UP }, | ||
207 | { ACTION_STD_CANCEL, BUTTON_POWER|BUTTON_REL, BUTTON_POWER }, | ||
208 | { ACTION_REC_NEWFILE, BUTTON_REC|BUTTON_REL, BUTTON_REC }, | ||
209 | { ACTION_STD_MENU, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, | ||
210 | { ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE }, | ||
211 | { ACTION_SETTINGS_INC, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
212 | { ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE }, | ||
213 | { ACTION_SETTINGS_DEC, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
214 | { ACTION_STD_PREV, BUTTON_SCROLL_UP, BUTTON_NONE }, | ||
215 | { ACTION_STD_PREV, BUTTON_SCROLL_UP|BUTTON_REPEAT, BUTTON_NONE }, | ||
216 | { ACTION_STD_NEXT, BUTTON_SCROLL_DOWN, BUTTON_NONE }, | ||
217 | { ACTION_STD_NEXT, BUTTON_SCROLL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, | ||
218 | |||
219 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | ||
220 | }; /* button_context_recscreen */ | ||
221 | |||
204 | static const struct button_mapping button_context_keyboard[] = { | 222 | static const struct button_mapping button_context_keyboard[] = { |
205 | { ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE }, | 223 | { ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE }, |
206 | { ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | 224 | { ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, |
@@ -272,6 +290,8 @@ const struct button_mapping* get_context_mapping(int context) | |||
272 | return button_context_quickscreen; | 290 | return button_context_quickscreen; |
273 | case CONTEXT_PITCHSCREEN: | 291 | case CONTEXT_PITCHSCREEN: |
274 | return button_context_pitchscreen; | 292 | return button_context_pitchscreen; |
293 | case CONTEXT_RECSCREEN: | ||
294 | return button_context_recscreen; | ||
275 | case CONTEXT_KEYBOARD: | 295 | case CONTEXT_KEYBOARD: |
276 | return button_context_keyboard; | 296 | return button_context_keyboard; |
277 | 297 | ||
diff --git a/apps/settings_list.c b/apps/settings_list.c index 23bb81ac51..f91cacf190 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c | |||
@@ -792,15 +792,21 @@ const struct settings_list settings[] = { | |||
792 | {F_T_INT|F_RECSETTING,&global_settings.cliplight,LANG_CLIP_LIGHT,INT(0), | 792 | {F_T_INT|F_RECSETTING,&global_settings.cliplight,LANG_CLIP_LIGHT,INT(0), |
793 | "cliplight","off,main,both,remote",UNUSED}, | 793 | "cliplight","off,main,both,remote",UNUSED}, |
794 | #endif | 794 | #endif |
795 | #ifdef DEFAULT_REC_MIC_GAIN | ||
795 | {F_T_INT|F_RECSETTING,&global_settings.rec_mic_gain, | 796 | {F_T_INT|F_RECSETTING,&global_settings.rec_mic_gain, |
796 | LANG_RECORDING_GAIN,INT(DEFAULT_REC_MIC_GAIN), | 797 | LANG_RECORDING_GAIN,INT(DEFAULT_REC_MIC_GAIN), |
797 | "rec mic gain",NULL,UNUSED}, | 798 | "rec mic gain",NULL,UNUSED}, |
799 | #endif /* DEFAULT_REC_MIC_GAIN */ | ||
800 | #ifdef DEFAULT_REC_LEFT_GAIN | ||
798 | {F_T_INT|F_RECSETTING,&global_settings.rec_left_gain, | 801 | {F_T_INT|F_RECSETTING,&global_settings.rec_left_gain, |
799 | LANG_RECORDING_LEFT,INT(DEFAULT_REC_LEFT_GAIN), | 802 | LANG_RECORDING_LEFT,INT(DEFAULT_REC_LEFT_GAIN), |
800 | "rec left gain",NULL,UNUSED}, | 803 | "rec left gain",NULL,UNUSED}, |
804 | #endif /* DEFAULT_REC_LEFT_GAIN */ | ||
805 | #ifdef DEFAULT_REC_RIGHT_GAIN | ||
801 | {F_T_INT|F_RECSETTING,&global_settings.rec_right_gain,LANG_RECORDING_RIGHT, | 806 | {F_T_INT|F_RECSETTING,&global_settings.rec_right_gain,LANG_RECORDING_RIGHT, |
802 | INT(DEFAULT_REC_RIGHT_GAIN), | 807 | INT(DEFAULT_REC_RIGHT_GAIN), |
803 | "rec right gain",NULL,UNUSED}, | 808 | "rec right gain",NULL,UNUSED}, |
809 | #endif /* DEFAULT_REC_RIGHT_GAIN */ | ||
804 | #if CONFIG_CODEC == MAS3587F | 810 | #if CONFIG_CODEC == MAS3587F |
805 | {F_T_INT|F_RECSETTING,&global_settings.rec_frequency, | 811 | {F_T_INT|F_RECSETTING,&global_settings.rec_frequency, |
806 | LANG_RECORDING_FREQUENCY, | 812 | LANG_RECORDING_FREQUENCY, |
diff --git a/firmware/SOURCES b/firmware/SOURCES index fdb457cbed..70bd12e0d5 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -296,7 +296,9 @@ target/arm/system-pp502x.c | |||
296 | target/arm/crt0-pp-bl.S | 296 | target/arm/crt0-pp-bl.S |
297 | #else | 297 | #else |
298 | target/arm/pcm-pp.c | 298 | target/arm/pcm-pp.c |
299 | #ifndef SANSA_E200 | ||
299 | target/arm/audio-pp.c | 300 | target/arm/audio-pp.c |
301 | #endif /* SANSA_E200 */ | ||
300 | target/arm/crt0-pp.S | 302 | target/arm/crt0-pp.S |
301 | #endif | 303 | #endif |
302 | #elif CONFIG_CPU == PNX0101 | 304 | #elif CONFIG_CPU == PNX0101 |
@@ -375,6 +377,9 @@ target/arm/usb-pp.c | |||
375 | target/arm/sandisk/sansa-e200/button-e200.c | 377 | target/arm/sandisk/sansa-e200/button-e200.c |
376 | target/arm/sandisk/sansa-e200/power-e200.c | 378 | target/arm/sandisk/sansa-e200/power-e200.c |
377 | target/arm/i2s-pp.c | 379 | target/arm/i2s-pp.c |
380 | #ifndef BOOTLOADER | ||
381 | target/arm/sandisk/sansa-e200/audio-e200.c | ||
382 | #endif /* BOOTLOADER */ | ||
378 | #endif /* SIMULATOR */ | 383 | #endif /* SIMULATOR */ |
379 | #endif /* SANSA_E200 */ | 384 | #endif /* SANSA_E200 */ |
380 | 385 | ||
diff --git a/firmware/drivers/audio/as3514.c b/firmware/drivers/audio/as3514.c index 3c11caa4c7..982bbe16d3 100644 --- a/firmware/drivers/audio/as3514.c +++ b/firmware/drivers/audio/as3514.c | |||
@@ -22,46 +22,76 @@ | |||
22 | #include "cpu.h" | 22 | #include "cpu.h" |
23 | #include "debug.h" | 23 | #include "debug.h" |
24 | #include "system.h" | 24 | #include "system.h" |
25 | #include "audio.h" | ||
25 | 26 | ||
26 | #include "audiohw.h" | 27 | #include "audiohw.h" |
27 | #include "i2s.h" | 28 | #include "i2s.h" |
28 | #include "i2c-pp.h" | 29 | #include "i2c-pp.h" |
29 | 30 | ||
30 | const struct sound_settings_info audiohw_settings[] = { | 31 | const struct sound_settings_info audiohw_settings[] = { |
31 | [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25}, | 32 | [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25}, |
32 | /* HAVE_SW_TONE_CONTROLS */ | 33 | /* HAVE_SW_TONE_CONTROLS */ |
33 | [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0}, | 34 | [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0}, |
34 | [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0}, | 35 | [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0}, |
35 | [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, | 36 | [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, |
36 | [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, | 37 | [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, |
37 | [SOUND_STEREO_WIDTH] = {"%", 0, 1, 0, 255, 100}, | 38 | [SOUND_STEREO_WIDTH] = {"%", 0, 1, 0, 255, 100}, |
39 | [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 39, 23}, | ||
40 | [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23}, | ||
41 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23}, | ||
38 | }; | 42 | }; |
39 | 43 | ||
40 | /* Shadow registers */ | 44 | /* Shadow registers */ |
41 | int as3514_regs[0x1E]; /* last audio register: PLLMODE 0x1d */ | 45 | struct as3514_info |
46 | { | ||
47 | int vol_r; /* Cached volume level (R) */ | ||
48 | int vol_l; /* Cached volume level (L) */ | ||
49 | unsigned int regs[0x1e]; /* last audio register: PLLMODE 0x1d */ | ||
50 | } as3514; | ||
51 | |||
52 | enum | ||
53 | { | ||
54 | SOURCE_DAC = 0, | ||
55 | SOURCE_MIC1, | ||
56 | SOURCE_LINE_IN1, | ||
57 | SOURCE_LINE_IN1_ANALOG | ||
58 | }; | ||
59 | |||
60 | static unsigned int source = SOURCE_DAC; | ||
42 | 61 | ||
43 | /* | 62 | /* |
44 | * little helper method to set register values. | 63 | * little helper method to set register values. |
45 | * With the help of as3514_regs, we minimize i2c | 64 | * With the help of as3514.regs, we minimize i2c |
46 | * traffic. | 65 | * traffic. |
47 | */ | 66 | */ |
48 | static void as3514_write(int reg, int value) | 67 | static void as3514_write(unsigned int reg, unsigned int value) |
49 | { | 68 | { |
50 | if (pp_i2c_send(AS3514_I2C_ADDR, reg, value) != 2) | 69 | if (pp_i2c_send(AS3514_I2C_ADDR, reg, value) != 2) |
51 | { | 70 | { |
52 | DEBUGF("as3514 error reg=0x%x", reg); | 71 | DEBUGF("as3514 error reg=0x%02x", reg); |
53 | } | 72 | } |
54 | 73 | ||
55 | if ((unsigned int)reg < sizeof(as3514_regs) / sizeof(int)) | 74 | if (reg < ARRAYLEN(as3514.regs)) |
56 | { | 75 | { |
57 | as3514_regs[reg] = value; | 76 | as3514.regs[reg] = value; |
58 | } | 77 | } |
59 | else | 78 | else |
60 | { | 79 | { |
61 | DEBUGF("as3514 error reg=0x%x", reg); | 80 | DEBUGF("as3514 error reg=0x%02x", reg); |
62 | } | 81 | } |
63 | } | 82 | } |
64 | 83 | ||
84 | /* Helpers to set/clear bits */ | ||
85 | static void as3514_write_or(unsigned int reg, unsigned int bits) | ||
86 | { | ||
87 | as3514_write(reg, as3514.regs[reg] | bits); | ||
88 | } | ||
89 | |||
90 | static void as3514_write_and(unsigned int reg, unsigned int bits) | ||
91 | { | ||
92 | as3514_write(reg, as3514.regs[reg] & bits); | ||
93 | } | ||
94 | |||
65 | /* convert tenth of dB volume to master volume register value */ | 95 | /* convert tenth of dB volume to master volume register value */ |
66 | int tenthdb2master(int db) | 96 | int tenthdb2master(int db) |
67 | { | 97 | { |
@@ -75,6 +105,26 @@ int tenthdb2master(int db) | |||
75 | } | 105 | } |
76 | } | 106 | } |
77 | 107 | ||
108 | int sound_val2phys(int setting, int value) | ||
109 | { | ||
110 | int result; | ||
111 | |||
112 | switch(setting) | ||
113 | { | ||
114 | case SOUND_LEFT_GAIN: | ||
115 | case SOUND_RIGHT_GAIN: | ||
116 | case SOUND_MIC_GAIN: | ||
117 | result = (value - 23) * 15; | ||
118 | break; | ||
119 | |||
120 | default: | ||
121 | result = value; | ||
122 | break; | ||
123 | } | ||
124 | |||
125 | return result; | ||
126 | } | ||
127 | |||
78 | void audiohw_reset(void); | 128 | void audiohw_reset(void); |
79 | 129 | ||
80 | /* | 130 | /* |
@@ -110,20 +160,33 @@ int audiohw_init(void) | |||
110 | i2s_reset(); | 160 | i2s_reset(); |
111 | 161 | ||
112 | /* Set ADC off, mixer on, DAC on, line out off, line in off, mic off */ | 162 | /* Set ADC off, mixer on, DAC on, line out off, line in off, mic off */ |
113 | as3514_write(AUDIOSET1, 0x64); /* Turn on SUM, DAC, LineIn 1 */ | 163 | |
114 | as3514_write(AUDIOSET3, 0x5); /* Set HPCM off, ZCU off*/ | 164 | /* Turn on SUM, DAC */ |
115 | as3514_write(HPH_OUT_R, 0xc0 | 0x16); /* set vol and set speaker over-current to 0 */ | 165 | as3514_write(AUDIOSET1, (1 << 6) | (1 << 5)); |
116 | as3514_write(HPH_OUT_L, 0x16); /* set default vol for headphone */ | 166 | |
117 | #if 0 | 167 | /* Set HPCM off, ZCU off*/ |
118 | as3514_write(LINE_IN1_R, 0x36); /* unmute lineIn 1 and set gain */ | 168 | as3514_write(AUDIOSET3, (1 << 2) | (1 << 0)); |
119 | as3514_write(LINE_IN1_L, 0x36); /* unmute lineIn 1 and set gain */ | 169 | |
120 | #endif | 170 | /* set vol and set speaker over-current to 0 */ |
171 | as3514_write(HPH_OUT_R, (0x3 << 6) | 0x16); | ||
172 | /* set default vol for headphone */ | ||
173 | as3514_write(HPH_OUT_L, 0x16); | ||
174 | |||
175 | /* LRCK 24-48kHz */ | ||
121 | as3514_write(PLLMODE, 0x00); | 176 | as3514_write(PLLMODE, 0x00); |
122 | 177 | ||
178 | /* DAC_Mute_off */ | ||
179 | as3514_write_or(DAC_L, (1 << 6)); | ||
180 | |||
181 | /* M1_Sup_off */ | ||
182 | as3514_write_or(MIC1_L, (1 << 7)); | ||
183 | /* M2_Sup_off */ | ||
184 | as3514_write_or(MIC2_L, (1 << 7)); | ||
185 | |||
123 | /* read all reg values */ | 186 | /* read all reg values */ |
124 | for (i = 0; i < sizeof(as3514_regs) / sizeof(int); i++) | 187 | for (i = 0; i < ARRAYLEN(as3514.regs); i++) |
125 | { | 188 | { |
126 | as3514_regs[i] = i2c_readbyte(AS3514_I2C_ADDR, i); | 189 | as3514.regs[i] = i2c_readbyte(AS3514_I2C_ADDR, i); |
127 | } | 190 | } |
128 | 191 | ||
129 | return 0; | 192 | return 0; |
@@ -136,75 +199,80 @@ void audiohw_postinit(void) | |||
136 | /* Silently enable / disable audio output */ | 199 | /* Silently enable / disable audio output */ |
137 | void audiohw_enable_output(bool enable) | 200 | void audiohw_enable_output(bool enable) |
138 | { | 201 | { |
139 | int curr; | 202 | if (enable) { |
140 | curr = as3514_regs[HPH_OUT_L]; | ||
141 | |||
142 | if (enable) | ||
143 | { | ||
144 | /* reset the I2S controller into known state */ | 203 | /* reset the I2S controller into known state */ |
145 | i2s_reset(); | 204 | i2s_reset(); |
146 | 205 | ||
147 | as3514_write(HPH_OUT_L, curr | 0x40); /* power on */ | 206 | as3514_write_or(HPH_OUT_L, (1 << 6)); /* power on */ |
148 | audiohw_mute(0); | 207 | audiohw_mute(0); |
149 | } else { | 208 | } else { |
150 | audiohw_mute(1); | 209 | audiohw_mute(1); |
151 | as3514_write(HPH_OUT_L, curr & ~(0x40)); /* power off */ | 210 | as3514_write_and(HPH_OUT_L, ~(1 << 6)); /* power off */ |
152 | } | 211 | } |
153 | } | 212 | } |
154 | 213 | ||
155 | int audiohw_set_master_vol(int vol_l, int vol_r) | 214 | int audiohw_set_master_vol(int vol_l, int vol_r) |
156 | { | 215 | { |
157 | int hph_r = as3514_regs[HPH_OUT_R] & ~0x1f; | 216 | unsigned int hph_r = as3514.regs[HPH_OUT_R] & ~0x1f; |
158 | int hph_l = as3514_regs[HPH_OUT_L] & ~0x1f; | 217 | unsigned int hph_l = as3514.regs[HPH_OUT_L] & ~0x1f; |
159 | 218 | unsigned int mix_l, mix_r; | |
160 | /* we are controling dac volume instead of headphone volume, | 219 | unsigned int mix_reg_r, mix_reg_l; |
161 | as the volume is bigger. | 220 | |
162 | HDP: 1.07 dB gain | 221 | /* keep track of current setting */ |
163 | DAC: 6 dB gain | 222 | as3514.vol_l = vol_l; |
164 | */ | 223 | as3514.vol_r = vol_r; |
165 | if(vol_r <= 0x16) | 224 | |
166 | { | 225 | if (source == SOURCE_LINE_IN1_ANALOG) { |
167 | as3514_write(DAC_R, vol_r); | 226 | mix_reg_r = LINE_IN1_R; |
168 | as3514_write(HPH_OUT_R, hph_r); /* set 0 */ | 227 | mix_reg_l = LINE_IN1_L; |
169 | } | 228 | } else { |
170 | else | 229 | mix_reg_r = DAC_R; |
171 | { | 230 | mix_reg_l = DAC_L; |
172 | as3514_write(DAC_R, 0x16); | ||
173 | as3514_write(HPH_OUT_R, hph_r + (vol_r - 0x16)); | ||
174 | } | 231 | } |
175 | 232 | ||
176 | if(vol_l <= 0x16) | 233 | mix_r = as3514.regs[mix_reg_r] & ~0x1f; |
177 | { | 234 | mix_l = as3514.regs[mix_reg_l] & ~0x1f; |
178 | as3514_write(DAC_L, 0x40 + vol_l); | 235 | |
179 | as3514_write(HPH_OUT_L, hph_l); /* set 0 */ | 236 | /* we combine the mixer channel volume range with the headphone volume |
237 | range */ | ||
238 | if (vol_r <= 0x16) { | ||
239 | mix_r |= vol_r; | ||
240 | /* hph_r - set 0 */ | ||
241 | } else { | ||
242 | mix_r |= 0x16; | ||
243 | hph_r += vol_r - 0x16; | ||
180 | } | 244 | } |
181 | else | 245 | |
182 | { | 246 | if (vol_l <= 0x16) { |
183 | as3514_write(DAC_L, 0x40 + 0x16); | 247 | mix_l |= vol_l; |
184 | as3514_write(HPH_OUT_L, hph_l + (vol_l - 0x16)); | 248 | /* hph_l - set 0 */ |
249 | } else { | ||
250 | mix_l |= 0x16; | ||
251 | hph_l += vol_l - 0x16; | ||
185 | } | 252 | } |
186 | 253 | ||
254 | as3514_write(mix_reg_r, mix_r); | ||
255 | as3514_write(mix_reg_l, mix_l); | ||
256 | as3514_write(HPH_OUT_R, hph_r); | ||
257 | as3514_write(HPH_OUT_L, hph_l); | ||
258 | |||
187 | return 0; | 259 | return 0; |
188 | } | 260 | } |
189 | 261 | ||
190 | int audiohw_set_lineout_vol(int vol_l, int vol_r) | 262 | int audiohw_set_lineout_vol(int vol_l, int vol_r) |
191 | { | 263 | { |
192 | as3514_write(LINE_OUT_R, vol_r); | 264 | as3514_write(LINE_OUT_R, vol_r); |
193 | as3514_write(LINE_OUT_L, 0x40 | vol_l); | 265 | as3514_write(LINE_OUT_L, (1 << 6) | vol_l); |
194 | 266 | ||
195 | return 0; | 267 | return 0; |
196 | } | 268 | } |
197 | 269 | ||
198 | int audiohw_mute(int mute) | 270 | int audiohw_mute(int mute) |
199 | { | 271 | { |
200 | int curr; | 272 | if (mute) { |
201 | curr = as3514_regs[HPH_OUT_L]; | 273 | as3514_write_or(HPH_OUT_L, (1 << 7)); |
202 | |||
203 | if (mute) | ||
204 | { | ||
205 | as3514_write(HPH_OUT_L, curr | 0x80); | ||
206 | } else { | 274 | } else { |
207 | as3514_write(HPH_OUT_L, curr & ~(0x80)); | 275 | as3514_write_and(HPH_OUT_L, ~(1 << 7)); |
208 | } | 276 | } |
209 | 277 | ||
210 | return 0; | 278 | return 0; |
@@ -214,7 +282,7 @@ int audiohw_mute(int mute) | |||
214 | void audiohw_close(void) | 282 | void audiohw_close(void) |
215 | { | 283 | { |
216 | /* mute headphones */ | 284 | /* mute headphones */ |
217 | audiohw_mute(1); | 285 | audiohw_mute(true); |
218 | 286 | ||
219 | /* turn off everything */ | 287 | /* turn off everything */ |
220 | as3514_write(AUDIOSET1, 0x0); | 288 | as3514_write(AUDIOSET1, 0x0); |
@@ -227,21 +295,124 @@ void audiohw_set_sample_rate(int sampling_control) | |||
227 | 295 | ||
228 | void audiohw_enable_recording(bool source_mic) | 296 | void audiohw_enable_recording(bool source_mic) |
229 | { | 297 | { |
230 | (void)source_mic; | 298 | if (source_mic) { |
299 | source = SOURCE_MIC1; | ||
300 | |||
301 | /* Sync mixer volumes before switching inputs */ | ||
302 | audiohw_set_master_vol(as3514.vol_l, as3514.vol_r); | ||
303 | |||
304 | /* ADCmux = Stereo Microphone */ | ||
305 | as3514_write_and(ADC_R, ~(0x3 << 6)); | ||
306 | /* MIC1_on, LIN1_off */ | ||
307 | as3514_write(AUDIOSET1, | ||
308 | (as3514.regs[AUDIOSET1] & ~(1 << 2)) | (1 << 0)); | ||
309 | /* M1_AGC_off */ | ||
310 | as3514_write_and(MIC1_R, ~(1 << 7)); | ||
311 | } else { | ||
312 | source = SOURCE_LINE_IN1; | ||
313 | |||
314 | audiohw_set_master_vol(as3514.vol_l, as3514.vol_r); | ||
315 | |||
316 | /* ADCmux = Line_IN1 */ | ||
317 | as3514_write(ADC_R, | ||
318 | (as3514.regs[ADC_R] & ~(0x3 << 6)) | (0x1 << 6)); | ||
319 | /* MIC1_off, LIN1_on */ | ||
320 | as3514_write(AUDIOSET1, | ||
321 | (as3514.regs[AUDIOSET1] & ~(1 << 0)) | (1 << 2)); | ||
322 | } | ||
323 | |||
324 | /* ADC_Mute_off */ | ||
325 | as3514_write_or(ADC_L, (1 << 6)); | ||
326 | /* ADC_on */ | ||
327 | as3514_write_or(AUDIOSET1, (1 << 7)); | ||
231 | } | 328 | } |
232 | 329 | ||
233 | void audiohw_disable_recording(void) | 330 | void audiohw_disable_recording(void) |
234 | { | 331 | { |
332 | source = SOURCE_DAC; | ||
333 | |||
334 | /* ADC_Mute_on */ | ||
335 | as3514_write_and(ADC_L, ~(1 << 6)); | ||
336 | |||
337 | /* ADC_off, LIN1_off, MIC_off */ | ||
338 | as3514_write_and(AUDIOSET1, ~((1 << 7) | (1 << 2) | (1 << 0))); | ||
339 | |||
340 | audiohw_set_master_vol(as3514.vol_l, as3514.vol_r); | ||
235 | } | 341 | } |
236 | 342 | ||
343 | /** | ||
344 | * Set recording volume | ||
345 | * | ||
346 | * Line in : 0 .. 23 .. 31 => | ||
347 | Volume -34.5 .. +00.0 .. +12.0 dB | ||
348 | * Mic (left): 0 .. 23 .. 39 => | ||
349 | * Volume -34.5 .. +00.0 .. +24.0 dB | ||
350 | * | ||
351 | */ | ||
237 | void audiohw_set_recvol(int left, int right, int type) | 352 | void audiohw_set_recvol(int left, int right, int type) |
238 | { | 353 | { |
239 | (void)left; | 354 | switch (type) |
240 | (void)right; | 355 | { |
241 | (void)type; | 356 | case AUDIO_GAIN_MIC: |
357 | { | ||
358 | /* Combine MIC gains seamlessly with ADC levels */ | ||
359 | unsigned int mic1_r = as3514.regs[MIC1_R] & ~(0x3 << 5); | ||
360 | |||
361 | if (left >= 36) { | ||
362 | /* M1_Gain = +40db, ADR_Vol = +7.5dB .. +12.0 dB => | ||
363 | +19.5 dB .. +24.0 dB */ | ||
364 | left -= 8; | ||
365 | mic1_r |= (0x2 << 5); | ||
366 | } else if (left >= 32) { | ||
367 | /* M1_Gain = +34db, ADR_Vol = +7.5dB .. +12.0 dB => | ||
368 | +13.5 dB .. +18.0 dB */ | ||
369 | left -= 4; | ||
370 | mic1_r |= (0x1 << 5); | ||
371 | } | ||
372 | /* M1_Gain = +28db, ADR_Vol = -34.5dB .. +12.0 dB => | ||
373 | -34.5 dB .. +12.0 dB */ | ||
374 | |||
375 | right = left; | ||
376 | |||
377 | as3514_write(MIC1_R, mic1_r); | ||
378 | break; | ||
379 | } | ||
380 | case AUDIO_GAIN_LINEIN: | ||
381 | break; | ||
382 | default: | ||
383 | return; | ||
384 | } | ||
385 | |||
386 | as3514_write(ADC_R, (as3514.regs[ADC_R] & ~0x1f) | right); | ||
387 | as3514_write(ADC_L, (as3514.regs[ADC_L] & ~0x1f) | left); | ||
242 | } | 388 | } |
243 | 389 | ||
390 | /** | ||
391 | * Enable line in 1 analog monitoring | ||
392 | * | ||
393 | */ | ||
244 | void audiohw_set_monitor(int enable) | 394 | void audiohw_set_monitor(int enable) |
245 | { | 395 | { |
246 | (void)enable; | 396 | /* LI1R_Mute_on - default */ |
397 | unsigned int line_in1_r = as3514.regs[LINE_IN1_R] & ~(1 << 5); | ||
398 | /* LI1L_Mute_on - default */ | ||
399 | unsigned int line_in1_l = as3514.regs[LINE_IN1_L] & ~(1 << 5); | ||
400 | /* LIN1_off - default */ | ||
401 | unsigned int audioset1 = as3514.regs[AUDIOSET1] & ~(1 << 2); | ||
402 | |||
403 | if (enable) { | ||
404 | source = SOURCE_LINE_IN1_ANALOG; | ||
405 | audiohw_set_master_vol(as3514.vol_l, as3514.vol_r); | ||
406 | |||
407 | /* LI1R_Mute_off */ | ||
408 | line_in1_r |= (1 << 5); | ||
409 | /* LI1L_Mute_off */ | ||
410 | line_in1_l |= (1 << 5); | ||
411 | /* LIN1_on */ | ||
412 | audioset1 |= (1 << 2); | ||
413 | } | ||
414 | |||
415 | as3514_write(AUDIOSET1, audioset1); | ||
416 | as3514_write(LINE_IN1_R, line_in1_r); | ||
417 | as3514_write(LINE_IN1_L, line_in1_l); | ||
247 | } | 418 | } |
diff --git a/firmware/export/audio.h b/firmware/export/audio.h index a0da846215..a79a734e29 100644 --- a/firmware/export/audio.h +++ b/firmware/export/audio.h | |||
@@ -139,6 +139,9 @@ enum audio_sources | |||
139 | AUDIO_SRC_DEFAULT = AUDIO_SRC_PLAYBACK | 139 | AUDIO_SRC_DEFAULT = AUDIO_SRC_PLAYBACK |
140 | }; | 140 | }; |
141 | 141 | ||
142 | extern int audio_channels; | ||
143 | extern int audio_output_source; | ||
144 | |||
142 | #ifdef HAVE_RECORDING | 145 | #ifdef HAVE_RECORDING |
143 | /* Recordable source implies it has the input as well */ | 146 | /* Recordable source implies it has the input as well */ |
144 | 147 | ||
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h index 3838b007d0..65a2466dfc 100644 --- a/firmware/export/audiohw.h +++ b/firmware/export/audiohw.h | |||
@@ -58,7 +58,8 @@ enum { | |||
58 | SOUND_SUPERBASS, | 58 | SOUND_SUPERBASS, |
59 | #endif | 59 | #endif |
60 | #if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320)\ | 60 | #if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320)\ |
61 | || defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8731) | 61 | || defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8731) \ |
62 | || defined(HAVE_AS3514) | ||
62 | SOUND_LEFT_GAIN, | 63 | SOUND_LEFT_GAIN, |
63 | SOUND_RIGHT_GAIN, | 64 | SOUND_RIGHT_GAIN, |
64 | SOUND_MIC_GAIN, | 65 | SOUND_MIC_GAIN, |
diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h index 9d4fb1ccef..001c89b7d7 100644 --- a/firmware/export/config-e200.h +++ b/firmware/export/config-e200.h | |||
@@ -7,11 +7,22 @@ | |||
7 | #define MODEL_NUMBER 16 | 7 | #define MODEL_NUMBER 16 |
8 | #define MODEL_NAME "Sandisk Sansa e200" | 8 | #define MODEL_NAME "Sandisk Sansa e200" |
9 | 9 | ||
10 | #define HW_SAMPR_CAPS (SAMPR_CAP_44) | ||
11 | |||
10 | /* define this if you have recording possibility */ | 12 | /* define this if you have recording possibility */ |
11 | /*#define HAVE_RECORDING*/ /* TODO: add support for this */ | 13 | #define HAVE_RECORDING |
14 | |||
15 | #define DEFAULT_REC_MIC_GAIN 23 | ||
16 | #define DEFAULT_REC_LEFT_GAIN 23 | ||
17 | #define DEFAULT_REC_RIGHT_GAIN 23 | ||
18 | |||
19 | #define REC_SAMPR_CAPS (SAMPR_CAP_22) | ||
20 | #define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */ | ||
21 | #define REC_SAMPR_DEFAULT SAMPR_22 | ||
22 | |||
12 | /* Define bitmask of input sources - recordable bitmask can be defined | 23 | /* Define bitmask of input sources - recordable bitmask can be defined |
13 | explicitly if different */ | 24 | explicitly if different */ |
14 | /* #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) */ | 25 | #define INPUT_SRC_CAPS (SRC_CAP_MIC) |
15 | 26 | ||
16 | /* define this if you have a bitmap LCD display */ | 27 | /* define this if you have a bitmap LCD display */ |
17 | #define HAVE_LCD_BITMAP | 28 | #define HAVE_LCD_BITMAP |
diff --git a/firmware/export/pcm_sampr.h b/firmware/export/pcm_sampr.h index 27a300d645..b27050ec60 100644 --- a/firmware/export/pcm_sampr.h +++ b/firmware/export/pcm_sampr.h | |||
@@ -292,18 +292,13 @@ enum rec_freq_indexes | |||
292 | #define REC_HAVE_8_(...) | 292 | #define REC_HAVE_8_(...) |
293 | #endif | 293 | #endif |
294 | REC_NUM_FREQ, | 294 | REC_NUM_FREQ, |
295 | /* This should always come out I reckon */ | ||
296 | REC_FREQ_DEFAULT = REC_FREQ_44, | ||
297 | /* Get the minimum bitcount needed to save the range of values */ | ||
298 | REC_FREQ_CFG_NUM_BITS = (REC_NUM_FREQ > 8 ? | ||
299 | 4 : (REC_NUM_FREQ > 4 ? | ||
300 | 3 : (REC_NUM_FREQ > 2 ? | ||
301 | 2 : 1 | ||
302 | ) | ||
303 | ) | ||
304 | ), | ||
305 | }; /* enum rec_freq_indexes */ | 295 | }; /* enum rec_freq_indexes */ |
306 | 296 | ||
297 | /* Default to 44.1kHz if not otherwise specified */ | ||
298 | #ifndef REC_FREQ_DEFAULT | ||
299 | #define REC_FREQ_DEFAULT REC_FREQ_44 | ||
300 | #endif | ||
301 | |||
307 | #define REC_FREQ_CFG_VAL_LIST &REC_HAVE_96_(",96") REC_HAVE_88_(",88") \ | 302 | #define REC_FREQ_CFG_VAL_LIST &REC_HAVE_96_(",96") REC_HAVE_88_(",88") \ |
308 | REC_HAVE_64_(",64") REC_HAVE_48_(",48") \ | 303 | REC_HAVE_64_(",64") REC_HAVE_48_(",48") \ |
309 | REC_HAVE_44_(",44") REC_HAVE_32_(",32") \ | 304 | REC_HAVE_44_(",44") REC_HAVE_32_(",32") \ |
diff --git a/firmware/sound.c b/firmware/sound.c index 9e4481c3c6..0ccf1df260 100644 --- a/firmware/sound.c +++ b/firmware/sound.c | |||
@@ -743,6 +743,7 @@ void sound_set(int setting, int value) | |||
743 | sound_set_val(value); | 743 | sound_set_val(value); |
744 | } | 744 | } |
745 | 745 | ||
746 | #ifndef HAVE_AS3514 | ||
746 | int sound_val2phys(int setting, int value) | 747 | int sound_val2phys(int setting, int value) |
747 | { | 748 | { |
748 | #if CONFIG_CODEC == MAS3587F | 749 | #if CONFIG_CODEC == MAS3587F |
@@ -804,6 +805,7 @@ int sound_val2phys(int setting, int value) | |||
804 | return value; | 805 | return value; |
805 | #endif | 806 | #endif |
806 | } | 807 | } |
808 | #endif /* HAVE_AS3514 */ | ||
807 | 809 | ||
808 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | 810 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) |
809 | #ifndef SIMULATOR | 811 | #ifndef SIMULATOR |
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c index 41bd92bd0d..9027ff13b3 100644 --- a/firmware/target/arm/pcm-pp.c +++ b/firmware/target/arm/pcm-pp.c | |||
@@ -160,7 +160,7 @@ void fiq(void) | |||
160 | { | 160 | { |
161 | /* Clear interrupt */ | 161 | /* Clear interrupt */ |
162 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 162 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
163 | IISCONFIG &= ~0x2; | 163 | IISCONFIG &= ~(1 << 1); |
164 | #elif CONFIG_CPU == PP5002 | 164 | #elif CONFIG_CPU == PP5002 |
165 | inl(0xcf001040); | 165 | inl(0xcf001040); |
166 | IISFIFO_CFG &= ~(1<<9); | 166 | IISFIFO_CFG &= ~(1<<9); |
@@ -171,7 +171,7 @@ void fiq(void) | |||
171 | if (FIFO_FREE_COUNT < 2) { | 171 | if (FIFO_FREE_COUNT < 2) { |
172 | /* Enable interrupt */ | 172 | /* Enable interrupt */ |
173 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 173 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
174 | IISCONFIG |= 0x2; | 174 | IISCONFIG |= (1 << 1); |
175 | #elif CONFIG_CPU == PP5002 | 175 | #elif CONFIG_CPU == PP5002 |
176 | IISFIFO_CFG |= (1<<9); | 176 | IISFIFO_CFG |= (1<<9); |
177 | #endif | 177 | #endif |
@@ -221,7 +221,7 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
221 | 221 | ||
222 | /* Enable playback FIFO */ | 222 | /* Enable playback FIFO */ |
223 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 223 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
224 | IISCONFIG |= 0x20000000; | 224 | IISCONFIG |= (1 << 29); |
225 | #elif CONFIG_CPU == PP5002 | 225 | #elif CONFIG_CPU == PP5002 |
226 | IISCONFIG |= 0x4; | 226 | IISCONFIG |= 0x4; |
227 | #endif | 227 | #endif |
@@ -232,7 +232,7 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
232 | if (FIFO_FREE_COUNT < 2) { | 232 | if (FIFO_FREE_COUNT < 2) { |
233 | /* Enable interrupt */ | 233 | /* Enable interrupt */ |
234 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 234 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
235 | IISCONFIG |= 0x2; | 235 | IISCONFIG |= (1 << 1); |
236 | #elif CONFIG_CPU == PP5002 | 236 | #elif CONFIG_CPU == PP5002 |
237 | IISFIFO_CFG |= (1<<9); | 237 | IISFIFO_CFG |= (1<<9); |
238 | #endif | 238 | #endif |
@@ -257,13 +257,8 @@ void pcm_play_dma_stop(void) | |||
257 | pcm_paused = false; | 257 | pcm_paused = false; |
258 | 258 | ||
259 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 259 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
260 | 260 | /* Disable playback FIFO and interrupt */ | |
261 | /* Disable playback FIFO */ | 261 | IISCONFIG &= ~((1 << 29) | (1 << 1)); |
262 | IISCONFIG &= ~0x20000000; | ||
263 | |||
264 | /* Disable the interrupt */ | ||
265 | IISCONFIG &= ~0x2; | ||
266 | |||
267 | #elif CONFIG_CPU == PP5002 | 262 | #elif CONFIG_CPU == PP5002 |
268 | 263 | ||
269 | /* Disable playback FIFO */ | 264 | /* Disable playback FIFO */ |
@@ -279,10 +274,8 @@ void pcm_play_dma_stop(void) | |||
279 | void pcm_play_pause_pause(void) | 274 | void pcm_play_pause_pause(void) |
280 | { | 275 | { |
281 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 276 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
282 | /* Disable the interrupt */ | 277 | /* Disable playback FIFO and interrupt */ |
283 | IISCONFIG &= ~0x2; | 278 | IISCONFIG &= ~((1 << 29) | (1 << 1)); |
284 | /* Disable playback FIFO */ | ||
285 | IISCONFIG &= ~0x20000000; | ||
286 | #elif CONFIG_CPU == PP5002 | 279 | #elif CONFIG_CPU == PP5002 |
287 | /* Disable the interrupt */ | 280 | /* Disable the interrupt */ |
288 | IISFIFO_CFG &= ~(1<<9); | 281 | IISFIFO_CFG &= ~(1<<9); |
@@ -301,7 +294,7 @@ void pcm_play_pause_unpause(void) | |||
301 | 294 | ||
302 | /* Enable playback FIFO */ | 295 | /* Enable playback FIFO */ |
303 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 296 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
304 | IISCONFIG |= 0x20000000; | 297 | IISCONFIG |= (1 << 29); |
305 | #elif CONFIG_CPU == PP5002 | 298 | #elif CONFIG_CPU == PP5002 |
306 | IISCONFIG |= 0x4; | 299 | IISCONFIG |= 0x4; |
307 | #endif | 300 | #endif |
@@ -312,7 +305,7 @@ void pcm_play_pause_unpause(void) | |||
312 | if (FIFO_FREE_COUNT < 2) { | 305 | if (FIFO_FREE_COUNT < 2) { |
313 | /* Enable interrupt */ | 306 | /* Enable interrupt */ |
314 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 307 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
315 | IISCONFIG |= 0x2; | 308 | IISCONFIG |= (1 << 1); |
316 | #elif CONFIG_CPU == PP5002 | 309 | #elif CONFIG_CPU == PP5002 |
317 | IISFIFO_CFG |= (1<<9); | 310 | IISFIFO_CFG |= (1<<9); |
318 | #endif | 311 | #endif |
@@ -369,6 +362,79 @@ void pcm_postinit(void) | |||
369 | ** Recording DMA transfer | 362 | ** Recording DMA transfer |
370 | **/ | 363 | **/ |
371 | #ifdef HAVE_RECORDING | 364 | #ifdef HAVE_RECORDING |
365 | |||
366 | #ifdef HAVE_AS3514 | ||
367 | void fiq_record(void) ICODE_ATTR __attribute__((naked)); | ||
368 | void fiq_record(void) | ||
369 | { | ||
370 | register pcm_more_callback_type2 more_ready; | ||
371 | register int32_t value1, value2; | ||
372 | |||
373 | asm volatile ("stmfd sp!, {r0-r7, ip, lr} \n"); /* Store context */ | ||
374 | |||
375 | IISCONFIG &= ~(1 << 0); | ||
376 | |||
377 | if (audio_channels == 2) { | ||
378 | /* RX is stereo */ | ||
379 | while (p_size > 0) { | ||
380 | if (FIFO_FREE_COUNT < 2) { | ||
381 | /* enable interrupt */ | ||
382 | IISCONFIG |= (1 << 0); | ||
383 | goto fiq_record_exit; | ||
384 | } | ||
385 | |||
386 | /* Discard every other sample since ADC clock is 1/2 LRCK */ | ||
387 | value1 = IISFIFO_RD; | ||
388 | value2 = IISFIFO_RD; | ||
389 | |||
390 | *(int32_t *)p = value1; | ||
391 | p += 2; | ||
392 | p_size -= 4; | ||
393 | |||
394 | /* TODO: Figure out how to do IIS loopback */ | ||
395 | if (audio_output_source != AUDIO_SRC_PLAYBACK) { | ||
396 | IISFIFO_WR = value1; | ||
397 | IISFIFO_WR = value1; | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | else { | ||
402 | /* RX is left channel mono */ | ||
403 | while (p_size > 0) { | ||
404 | if (FIFO_FREE_COUNT < 2) { | ||
405 | /* enable interrupt */ | ||
406 | IISCONFIG |= (1 << 0); | ||
407 | goto fiq_record_exit; | ||
408 | } | ||
409 | |||
410 | /* Discard every other sample since ADC clock is 1/2 LRCK */ | ||
411 | value1 = IISFIFO_RD; | ||
412 | value2 = IISFIFO_RD; | ||
413 | *p++ = value1; | ||
414 | *p++ = value1; | ||
415 | p_size -= 4; | ||
416 | |||
417 | if (audio_output_source != AUDIO_SRC_PLAYBACK) { | ||
418 | value1 = *((int32_t *)p - 1); | ||
419 | IISFIFO_WR = value1; | ||
420 | IISFIFO_WR = value1; | ||
421 | } | ||
422 | } | ||
423 | } | ||
424 | |||
425 | more_ready = pcm_callback_more_ready; | ||
426 | |||
427 | if (more_ready == NULL || more_ready(0) < 0) { | ||
428 | /* Finished recording */ | ||
429 | pcm_rec_dma_stop(); | ||
430 | } | ||
431 | |||
432 | fiq_record_exit: | ||
433 | asm volatile("ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */ | ||
434 | "subs pc, lr, #4 \n"); /* Return from FIQ */ | ||
435 | } | ||
436 | |||
437 | #else | ||
372 | static short peak_l, peak_r IBSS_ATTR; | 438 | static short peak_l, peak_r IBSS_ATTR; |
373 | 439 | ||
374 | void fiq_record(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); | 440 | void fiq_record(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); |
@@ -380,7 +446,7 @@ void fiq_record(void) | |||
380 | 446 | ||
381 | /* Clear interrupt */ | 447 | /* Clear interrupt */ |
382 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 448 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
383 | IISCONFIG &= ~0x01; | 449 | IISCONFIG &= ~(1 << 0); |
384 | #elif CONFIG_CPU == PP5002 | 450 | #elif CONFIG_CPU == PP5002 |
385 | /* TODO */ | 451 | /* TODO */ |
386 | #endif | 452 | #endif |
@@ -389,12 +455,13 @@ void fiq_record(void) | |||
389 | if (FIFO_FREE_COUNT < 2) { | 455 | if (FIFO_FREE_COUNT < 2) { |
390 | /* enable interrupt */ | 456 | /* enable interrupt */ |
391 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 457 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
392 | IISCONFIG |= 0x01; | 458 | IISCONFIG |= (1 << 0); |
393 | #elif CONFIG_CPU == PP5002 | 459 | #elif CONFIG_CPU == PP5002 |
394 | /* TODO */ | 460 | /* TODO */ |
395 | #endif | 461 | #endif |
396 | return; | 462 | return; |
397 | } | 463 | } |
464 | |||
398 | value = (unsigned short)(IISFIFO_RD >> 16); | 465 | value = (unsigned short)(IISFIFO_RD >> 16); |
399 | if (value > peak_l) peak_l = value; | 466 | if (value > peak_l) peak_l = value; |
400 | else if (-value > peak_l) peak_l = -value; | 467 | else if (-value > peak_l) peak_l = -value; |
@@ -424,16 +491,18 @@ void fiq_record(void) | |||
424 | pcm_rec_dma_stop(); | 491 | pcm_rec_dma_stop(); |
425 | } | 492 | } |
426 | 493 | ||
494 | #endif /* HAVE_AS3514 */ | ||
495 | |||
427 | /* Continue transferring data in */ | 496 | /* Continue transferring data in */ |
428 | void pcm_record_more(void *start, size_t size) | 497 | void pcm_record_more(void *start, size_t size) |
429 | { | 498 | { |
430 | rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */ | 499 | rec_peak_addr = start; /* Start peaking at dest */ |
431 | p = start; | 500 | p = start; /* Start of RX buffer */ |
432 | p_size = size; /* Bytes to transfer */ | 501 | p_size = size; /* Bytes to transfer */ |
433 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 | 502 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
434 | IISCONFIG |= 0x01; | 503 | IISCONFIG |= (1 << 0); |
435 | #elif CONFIG_CPU == PP5002 | 504 | #elif CONFIG_CPU == PP5002 |
436 | /* TODO */ | 505 | /* TODO */ |
437 | #endif | 506 | #endif |
438 | } | 507 | } |
439 | 508 | ||
@@ -441,11 +510,14 @@ void pcm_rec_dma_stop(void) | |||
441 | { | 510 | { |
442 | logf("pcm_rec_dma_stop"); | 511 | logf("pcm_rec_dma_stop"); |
443 | 512 | ||
444 | /* disable fifo */ | ||
445 | IISCONFIG &= ~0x10000000; | ||
446 | |||
447 | disable_fiq(); | 513 | disable_fiq(); |
448 | 514 | ||
515 | /* clear interrupt, disable fifo */ | ||
516 | IISCONFIG &= ~((1 << 28) | (1 << 0)); | ||
517 | |||
518 | /* clear rx fifo */ | ||
519 | IISFIFO_CFG |= (1 << 12); | ||
520 | |||
449 | pcm_recording = false; | 521 | pcm_recording = false; |
450 | } | 522 | } |
451 | 523 | ||
@@ -455,7 +527,10 @@ void pcm_rec_dma_start(void *addr, size_t size) | |||
455 | 527 | ||
456 | pcm_recording = true; | 528 | pcm_recording = true; |
457 | 529 | ||
530 | #ifndef HAVE_AS3514 | ||
458 | peak_l = peak_r = 0; | 531 | peak_l = peak_r = 0; |
532 | #endif | ||
533 | |||
459 | p_size = size; | 534 | p_size = size; |
460 | p = addr; | 535 | p = addr; |
461 | 536 | ||
@@ -463,11 +538,8 @@ void pcm_rec_dma_start(void *addr, size_t size) | |||
463 | CPU_INT_PRIORITY |= I2S_MASK; | 538 | CPU_INT_PRIORITY |= I2S_MASK; |
464 | CPU_INT_EN = I2S_MASK; | 539 | CPU_INT_EN = I2S_MASK; |
465 | 540 | ||
466 | /* interrupt on full fifo */ | 541 | /* interrupt on full fifo, enable record fifo */ |
467 | IISCONFIG |= 0x1; | 542 | IISCONFIG |= (1 << 28) | (1 << 0); |
468 | |||
469 | /* enable record fifo */ | ||
470 | IISCONFIG |= 0x10000000; | ||
471 | 543 | ||
472 | set_fiq_handler(fiq_record); | 544 | set_fiq_handler(fiq_record); |
473 | enable_fiq(); | 545 | enable_fiq(); |
@@ -476,18 +548,7 @@ void pcm_rec_dma_start(void *addr, size_t size) | |||
476 | void pcm_close_recording(void) | 548 | void pcm_close_recording(void) |
477 | { | 549 | { |
478 | logf("pcm_close_recording"); | 550 | logf("pcm_close_recording"); |
479 | |||
480 | pcm_rec_dma_stop(); | 551 | pcm_rec_dma_stop(); |
481 | |||
482 | #if (CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024) | ||
483 | disable_fiq(); | ||
484 | |||
485 | /* disable fifo */ | ||
486 | IISCONFIG &= ~0x10000000; | ||
487 | |||
488 | /* Clear interrupt */ | ||
489 | IISCONFIG &= ~0x01; | ||
490 | #endif | ||
491 | } /* pcm_close_recording */ | 552 | } /* pcm_close_recording */ |
492 | 553 | ||
493 | void pcm_init_recording(void) | 554 | void pcm_init_recording(void) |
@@ -505,7 +566,7 @@ void pcm_init_recording(void) | |||
505 | GPIOA_OUTPUT_VAL &= ~0x4; | 566 | GPIOA_OUTPUT_VAL &= ~0x4; |
506 | #endif | 567 | #endif |
507 | /* Setup the recording FIQ handler */ | 568 | /* Setup the recording FIQ handler */ |
508 | *((unsigned int*)(15*4)) = (unsigned int)&fiq_record; | 569 | set_fiq_handler(fiq_record); |
509 | #endif | 570 | #endif |
510 | 571 | ||
511 | pcm_rec_dma_stop(); | 572 | pcm_rec_dma_stop(); |
@@ -513,10 +574,57 @@ void pcm_init_recording(void) | |||
513 | 574 | ||
514 | void pcm_calculate_rec_peaks(int *left, int *right) | 575 | void pcm_calculate_rec_peaks(int *left, int *right) |
515 | { | 576 | { |
516 | *left = rec_peak_left; | 577 | #ifdef HAVE_AS3514 |
517 | *right = rec_peak_right; | 578 | if (pcm_recording) |
579 | { | ||
580 | unsigned long *start = rec_peak_addr; | ||
581 | unsigned long *end = (unsigned long *)p; | ||
582 | |||
583 | if (start < end) | ||
584 | { | ||
585 | unsigned long *addr = start; | ||
586 | long peak_l = 0, peak_r = 0; | ||
587 | long peaksq_l = 0, peaksq_r = 0; | ||
588 | |||
589 | do | ||
590 | { | ||
591 | long value = *addr; | ||
592 | long ch, chsq; | ||
593 | |||
594 | ch = (int16_t)value; | ||
595 | chsq = ch*ch; | ||
596 | if (chsq > peaksq_l) | ||
597 | peak_l = ch, peaksq_l = chsq; | ||
598 | |||
599 | ch = value >> 16; | ||
600 | chsq = ch*ch; | ||
601 | if (chsq > peaksq_r) | ||
602 | peak_r = ch, peaksq_r = chsq; | ||
603 | |||
604 | addr += 4; | ||
605 | } | ||
606 | while (addr < end); | ||
607 | |||
608 | if (start == rec_peak_addr) | ||
609 | rec_peak_addr = end; | ||
610 | |||
611 | rec_peak_left = abs(peak_l); | ||
612 | rec_peak_right = abs(peak_r); | ||
613 | } | ||
614 | } | ||
615 | else | ||
616 | { | ||
617 | rec_peak_left = rec_peak_right = 0; | ||
618 | } | ||
619 | #endif /* HAVE_AS3514 */ | ||
620 | |||
621 | if (left) | ||
622 | *left = rec_peak_left; | ||
623 | |||
624 | if (right) | ||
625 | *right = rec_peak_right; | ||
518 | } | 626 | } |
519 | #endif | 627 | #endif /* HAVE_RECORDING */ |
520 | 628 | ||
521 | /* | 629 | /* |
522 | * This function goes directly into the DMA buffer to calculate the left and | 630 | * This function goes directly into the DMA buffer to calculate the left and |
diff --git a/firmware/target/arm/sandisk/sansa-e200/ata-e200.c b/firmware/target/arm/sandisk/sansa-e200/ata-e200.c index 29fe0d9109..10c13cdb2e 100644 --- a/firmware/target/arm/sandisk/sansa-e200/ata-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/ata-e200.c | |||
@@ -223,6 +223,7 @@ void sd_wait_for_state(tSDCardInfo* card, unsigned int state) | |||
223 | while(((response >> 9) & 0xf) != state) | 223 | while(((response >> 9) & 0xf) != state) |
224 | { | 224 | { |
225 | sd_send_command(SEND_STATUS, (card->rca) << 16, 1); | 225 | sd_send_command(SEND_STATUS, (card->rca) << 16, 1); |
226 | priority_yield(); | ||
226 | sd_read_response(&response, 1); | 227 | sd_read_response(&response, 1); |
227 | /* TODO: Add a timeout and error handling */ | 228 | /* TODO: Add a timeout and error handling */ |
228 | } | 229 | } |
@@ -442,7 +443,7 @@ void sd_init_device(void) | |||
442 | dataptr += (FIFO_SIZE*2); /* Advance one chunk of 16 words */ | 443 | dataptr += (FIFO_SIZE*2); /* Advance one chunk of 16 words */ |
443 | } | 444 | } |
444 | } | 445 | } |
445 | mutex_init(&sd_mtx); | 446 | spinlock_init(&sd_mtx); |
446 | } | 447 | } |
447 | 448 | ||
448 | /* API Functions */ | 449 | /* API Functions */ |
@@ -472,7 +473,7 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
472 | #ifdef HAVE_MULTIVOLUME | 473 | #ifdef HAVE_MULTIVOLUME |
473 | (void)drive; /* unused for now */ | 474 | (void)drive; /* unused for now */ |
474 | #endif | 475 | #endif |
475 | mutex_lock(&sd_mtx); | 476 | spinlock_lock(&sd_mtx); |
476 | 477 | ||
477 | last_disk_activity = current_tick; | 478 | last_disk_activity = current_tick; |
478 | spinup_start = current_tick; | 479 | spinup_start = current_tick; |
@@ -530,7 +531,7 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
530 | ata_led(false); | 531 | ata_led(false); |
531 | ata_enable(false); | 532 | ata_enable(false); |
532 | 533 | ||
533 | mutex_unlock(&sd_mtx); | 534 | spinlock_unlock(&sd_mtx); |
534 | 535 | ||
535 | return ret; | 536 | return ret; |
536 | } | 537 | } |
@@ -551,7 +552,7 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
551 | long timeout; | 552 | long timeout; |
552 | tSDCardInfo *card = &card_info[current_card]; | 553 | tSDCardInfo *card = &card_info[current_card]; |
553 | 554 | ||
554 | mutex_lock(&sd_mtx); | 555 | spinlock_lock(&sd_mtx); |
555 | ata_enable(true); | 556 | ata_enable(true); |
556 | ata_led(true); | 557 | ata_led(true); |
557 | if(current_card == 0) | 558 | if(current_card == 0) |
@@ -607,7 +608,7 @@ retry: | |||
607 | sd_wait_for_state(card, TRAN); | 608 | sd_wait_for_state(card, TRAN); |
608 | ata_led(false); | 609 | ata_led(false); |
609 | ata_enable(false); | 610 | ata_enable(false); |
610 | mutex_unlock(&sd_mtx); | 611 | spinlock_unlock(&sd_mtx); |
611 | 612 | ||
612 | return ret; | 613 | return ret; |
613 | } | 614 | } |
diff --git a/firmware/target/arm/sandisk/sansa-e200/audio-e200.c b/firmware/target/arm/sandisk/sansa-e200/audio-e200.c new file mode 100644 index 0000000000..a3f3284b98 --- /dev/null +++ b/firmware/target/arm/sandisk/sansa-e200/audio-e200.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Michael Sevakis | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "system.h" | ||
20 | #include "cpu.h" | ||
21 | #include "audio.h" | ||
22 | #include "sound.h" | ||
23 | |||
24 | int audio_channels = 2; | ||
25 | int audio_output_source = AUDIO_SRC_PLAYBACK; | ||
26 | |||
27 | void audio_set_output_source(int source) | ||
28 | { | ||
29 | int oldmode = set_fiq_status(FIQ_DISABLED); | ||
30 | |||
31 | if ((unsigned)source >= AUDIO_NUM_SOURCES) | ||
32 | source = AUDIO_SRC_PLAYBACK; | ||
33 | |||
34 | audio_output_source = source; | ||
35 | |||
36 | if (source != AUDIO_SRC_PLAYBACK) | ||
37 | IISCONFIG |= (1 << 29); | ||
38 | |||
39 | set_fiq_status(oldmode); | ||
40 | } /* audio_set_output_source */ | ||
41 | |||
42 | void audio_set_source(int source, unsigned flags) | ||
43 | { | ||
44 | static int last_source = AUDIO_SRC_PLAYBACK; | ||
45 | #if 0 | ||
46 | static bool last_recording = false; | ||
47 | bool recording = flags & SRCF_RECORDING; | ||
48 | #endif | ||
49 | (void)flags; | ||
50 | |||
51 | switch (source) | ||
52 | { | ||
53 | default: /* playback - no recording */ | ||
54 | source = AUDIO_SRC_PLAYBACK; | ||
55 | case AUDIO_SRC_PLAYBACK: | ||
56 | audio_channels = 2; | ||
57 | if (source != last_source) | ||
58 | { | ||
59 | audiohw_set_monitor(false); | ||
60 | audiohw_disable_recording(); | ||
61 | } | ||
62 | break; | ||
63 | |||
64 | case AUDIO_SRC_MIC: /* recording only */ | ||
65 | audio_channels = 1; | ||
66 | if (source != last_source) | ||
67 | { | ||
68 | audiohw_set_monitor(false); | ||
69 | audiohw_enable_recording(true); /* source mic */ | ||
70 | } | ||
71 | break; | ||
72 | |||
73 | #if 0 | ||
74 | case AUDIO_SRC_FMRADIO: /* recording and playback */ | ||
75 | audio_channels = 2; | ||
76 | |||
77 | if (!recording) | ||
78 | audiohw_set_recvol(23, 23, AUDIO_GAIN_LINEIN); | ||
79 | |||
80 | if (source == last_source && recording == last_recording) | ||
81 | break; | ||
82 | |||
83 | last_recording = recording; | ||
84 | |||
85 | if (recording) | ||
86 | { | ||
87 | audiohw_set_monitor(false); | ||
88 | audiohw_enable_recording(false); | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | audiohw_disable_recording(); | ||
93 | audiohw_set_monitor(true); /* line 1 analog audio path */ | ||
94 | } | ||
95 | |||
96 | break; | ||
97 | #endif | ||
98 | } /* end switch */ | ||
99 | |||
100 | last_source = source; | ||
101 | } /* audio_set_source */ | ||
102 | |||
103 | |||