summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Wardell <rockbox@barrywardell.net>2006-12-18 01:52:21 +0000
committerBarry Wardell <rockbox@barrywardell.net>2006-12-18 01:52:21 +0000
commitdf0dc2262ea10f621677c0f97aae1c205e253b87 (patch)
treed25085132fe9f0504d221360092537492cedd3b8
parent440353a9aa1159584b977a2852e723ae07bad2a6 (diff)
downloadrockbox-df0dc2262ea10f621677c0f97aae1c205e253b87.tar.gz
rockbox-df0dc2262ea10f621677c0f97aae1c205e253b87.zip
FS#6096. Recording on PortalPlayer targets (H10, iPod Video, iPod 4g, iPod Color, iPod Nano).
* Fix failed compile of enc_config.c when HAVE_MPEG2_SAMPR is not defined. * Fix bug in AIFF encoder header creation on little endian targets. * Add recording screen keymaps for H10 and iPod. * Move pcm_playback PP specific code to target tree. * Add recording code to wmcodec drivers. * Add pcm_record code. Some problems still remain: * Playback doesn't work after recording until Rockbox is restarted. * Gain control not implemented. * Only 16-bit/44KHz for now. The hardware should be capable of up to 24-bit/96KHz. * Line-in recording not tested on H10. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11794 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs/aiff_enc.c2
-rw-r--r--apps/enc_config.c4
-rw-r--r--apps/keymaps/keymap-h10.c10
-rw-r--r--apps/keymaps/keymap-ipod.c8
-rw-r--r--apps/main.c3
-rw-r--r--apps/settings.c21
-rw-r--r--firmware/SOURCES2
-rw-r--r--firmware/drivers/wm8731l.c65
-rw-r--r--firmware/drivers/wm8758.c72
-rw-r--r--firmware/drivers/wm8975.c73
-rw-r--r--firmware/export/config-h10.h8
-rw-r--r--firmware/export/config-h10_5gb.h8
-rw-r--r--firmware/export/config-ipod4g.h8
-rw-r--r--firmware/export/config-ipodcolor.h8
-rw-r--r--firmware/export/config-ipodnano.h8
-rw-r--r--firmware/export/config-ipodvideo.h8
-rw-r--r--firmware/export/sound.h3
-rw-r--r--firmware/export/system.h5
-rw-r--r--firmware/export/wm8731l.h1
-rw-r--r--firmware/export/wm8758.h5
-rw-r--r--firmware/pcm_playback.c328
-rw-r--r--firmware/sound.c14
-rw-r--r--firmware/target/arm/audio-pp.c84
-rw-r--r--firmware/target/arm/pcm-pp.c578
24 files changed, 959 insertions, 367 deletions
diff --git a/apps/codecs/aiff_enc.c b/apps/codecs/aiff_enc.c
index aca1951654..f1569d20ff 100644
--- a/apps/codecs/aiff_enc.c
+++ b/apps/codecs/aiff_enc.c
@@ -59,7 +59,7 @@ struct aiff_header aiff_header =
59 H_TO_BE32(18), /* comm_size */ 59 H_TO_BE32(18), /* comm_size */
60 0, /* num_channels (*) */ 60 0, /* num_channels (*) */
61 0, /* num_sample_frames (*) */ 61 0, /* num_sample_frames (*) */
62 H_TO_BE32(PCM_DEPTH_BITS), /* sample_size */ 62 H_TO_BE16(PCM_DEPTH_BITS), /* sample_size */
63 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* sample_rate (*) */ 63 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* sample_rate (*) */
64 { 'S', 'S', 'N', 'D' }, /* ssnd_id */ 64 { 'S', 'S', 'N', 'D' }, /* ssnd_id */
65 0, /* ssnd_size (*) */ 65 0, /* ssnd_size (*) */
diff --git a/apps/enc_config.c b/apps/enc_config.c
index 2d2abae61a..f4ea1cc4b5 100644
--- a/apps/enc_config.c
+++ b/apps/enc_config.c
@@ -159,9 +159,9 @@ static bool mp3_enc_bitrate(struct encoder_config *cfg)
159 MPEG1_BITR_CAPS | MPEG2_BITR_CAPS, mp3_enc_bitr, 159 MPEG1_BITR_CAPS | MPEG2_BITR_CAPS, mp3_enc_bitr,
160 MPEG1_BITR_CAPS 160 MPEG1_BITR_CAPS
161#ifdef HAVE_MPEG2_SAMPR 161#ifdef HAVE_MPEG2_SAMPR
162 | (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_144 | MP3_BITR_CAP_8)), 162 | (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_144 | MP3_BITR_CAP_8))
163#endif 163#endif
164 rate_list); 164 , rate_list);
165 165
166 int index = round_value_to_list32(cfg->mp3_enc.bitrate, rate_list, 166 int index = round_value_to_list32(cfg->mp3_enc.bitrate, rate_list,
167 n_rates, false); 167 n_rates, false);
diff --git a/apps/keymaps/keymap-h10.c b/apps/keymaps/keymap-h10.c
index 33bcb13269..16c8c49258 100644
--- a/apps/keymaps/keymap-h10.c
+++ b/apps/keymaps/keymap-h10.c
@@ -298,6 +298,12 @@ static const struct button_mapping button_context_bmark[] = {
298 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), 298 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
299}; /* button_context_bmark */ 299}; /* button_context_bmark */
300 300
301const struct button_mapping button_context_recscreen[] = {
302 { ACTION_REC_PAUSE, BUTTON_PLAY, BUTTON_NONE },
303
304 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
305}; /* button_context_recscreen */
306
301static const struct button_mapping* get_context_mapping_remote( int context ) 307static const struct button_mapping* get_context_mapping_remote( int context )
302{ 308{
303 context ^= CONTEXT_REMOTE; 309 context ^= CONTEXT_REMOTE;
@@ -325,6 +331,8 @@ static const struct button_mapping* get_context_mapping_remote( int context )
325 return remote_button_context_quickscreen; 331 return remote_button_context_quickscreen;
326 case CONTEXT_PITCHSCREEN: 332 case CONTEXT_PITCHSCREEN:
327 return remote_button_context_pitchscreen; 333 return remote_button_context_pitchscreen;
334 case CONTEXT_RECSCREEN:
335 return button_context_recscreen;
328 336
329 default: 337 default:
330 return remote_button_context_standard; 338 return remote_button_context_standard;
@@ -374,6 +382,8 @@ const struct button_mapping* get_context_mapping(int context)
374 return button_context_pitchscreen; 382 return button_context_pitchscreen;
375 case CONTEXT_KEYBOARD: 383 case CONTEXT_KEYBOARD:
376 return button_context_keyboard; 384 return button_context_keyboard;
385 case CONTEXT_RECSCREEN:
386 return button_context_recscreen;
377 387
378 default: 388 default:
379 return button_context_standard; 389 return button_context_standard;
diff --git a/apps/keymaps/keymap-ipod.c b/apps/keymaps/keymap-ipod.c
index 26189d95fe..8ca0c56831 100644
--- a/apps/keymaps/keymap-ipod.c
+++ b/apps/keymaps/keymap-ipod.c
@@ -166,6 +166,12 @@ static const struct button_mapping button_context_keyboard[] = {
166 LAST_ITEM_IN_LIST 166 LAST_ITEM_IN_LIST
167}; /* button_context_keyboard */ 167}; /* button_context_keyboard */
168 168
169const struct button_mapping button_context_recscreen[] = {
170 { ACTION_REC_PAUSE, BUTTON_PLAY, BUTTON_NONE },
171
172 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
173}; /* button_context_recscreen */
174
169/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */ 175/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
170const struct button_mapping* get_context_mapping(int context) 176const struct button_mapping* get_context_mapping(int context)
171{ 177{
@@ -202,6 +208,8 @@ const struct button_mapping* get_context_mapping(int context)
202 return button_context_pitchscreen; 208 return button_context_pitchscreen;
203 case CONTEXT_KEYBOARD: 209 case CONTEXT_KEYBOARD:
204 return button_context_keyboard; 210 return button_context_keyboard;
211 case CONTEXT_RECSCREEN:
212 return button_context_recscreen;
205 default: 213 default:
206 return button_context_standard; 214 return button_context_standard;
207 } 215 }
diff --git a/apps/main.c b/apps/main.c
index abc7740919..f9e6054973 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -78,6 +78,9 @@
78#endif 78#endif
79#if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && !defined(SIMULATOR) 79#if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && !defined(SIMULATOR)
80#include "pcm_record.h" 80#include "pcm_record.h"
81#endif
82
83#ifdef BUTTON_REC
81#define SETTINGS_RESET BUTTON_REC 84#define SETTINGS_RESET BUTTON_REC
82#endif 85#endif
83 86
diff --git a/apps/settings.c b/apps/settings.c
index 91ffc0d238..454ba183ee 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -100,7 +100,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
100#include "eq_menu.h" 100#include "eq_menu.h"
101#endif 101#endif
102 102
103#define CONFIG_BLOCK_VERSION 56 103#define CONFIG_BLOCK_VERSION 57
104#define CONFIG_BLOCK_SIZE 512 104#define CONFIG_BLOCK_SIZE 512
105#define RTC_BLOCK_SIZE 44 105#define RTC_BLOCK_SIZE 44
106 106
@@ -521,13 +521,26 @@ static const struct bit_entry hd_bits[] =
521#if CONFIG_CODEC == SWCODEC 521#if CONFIG_CODEC == SWCODEC
522#ifdef HAVE_UDA1380 522#ifdef HAVE_UDA1380
523 {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */ 523 {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
524#endif 524 {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
525#ifdef HAVE_TLV320 525 {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
526#elif defined(HAVE_TLV320)
526 /* TLV320 only has no mic boost or 20db mic boost */ 527 /* TLV320 only has no mic boost or 20db mic boost */
527 {1, S_O(rec_mic_gain), 0 /* 0 dB */, "rec mic gain", NULL }, /* 0db or 20db */ 528 {1, S_O(rec_mic_gain), 0 /* 0 dB */, "rec mic gain", NULL }, /* 0db or 20db */
528#endif
529 {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */ 529 {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
530 {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */ 530 {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
531#elif defined(HAVE_WM8975)
532 {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
533 {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
534 {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
535#elif defined(HAVE_WM8758)
536 {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
537 {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
538 {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
539#elif defined(HAVE_WM8731)
540 {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
541 {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
542 {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
543#endif
531 {REC_FREQ_CFG_NUM_BITS, S_O(rec_frequency), REC_FREQ_DEFAULT, 544 {REC_FREQ_CFG_NUM_BITS, S_O(rec_frequency), REC_FREQ_DEFAULT,
532 "rec frequency", REC_FREQ_CFG_VAL_LIST }, 545 "rec frequency", REC_FREQ_CFG_VAL_LIST },
533 {REC_FORMAT_CFG_NUM_BITS ,S_O(rec_format), REC_FORMAT_DEFAULT, 546 {REC_FORMAT_CFG_NUM_BITS ,S_O(rec_format), REC_FORMAT_DEFAULT,
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 30431d71b2..11242a062c 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -262,6 +262,8 @@ drivers/i2c-pnx0101.c
262/* no i2c driver yet */ 262/* no i2c driver yet */
263#endif 263#endif
264#if defined(CPU_PP) 264#if defined(CPU_PP)
265target/arm/pcm-pp.c
266target/arm/audio-pp.c
265target/arm/crt0-pp.S 267target/arm/crt0-pp.S
266#elif defined(CPU_ARM) 268#elif defined(CPU_ARM)
267target/arm/crt0.S 269target/arm/crt0.S
diff --git a/firmware/drivers/wm8731l.c b/firmware/drivers/wm8731l.c
index a690aade48..4f0f249149 100644
--- a/firmware/drivers/wm8731l.c
+++ b/firmware/drivers/wm8731l.c
@@ -220,12 +220,73 @@ void audiohw_set_sample_rate(int sampling_control)
220 220
221void audiohw_enable_recording(bool source_mic) 221void audiohw_enable_recording(bool source_mic)
222{ 222{
223 (void)source_mic; 223 static int line_level = 0x17;
224 static int mic_boost = true;
225 codec_set_active(0x0);
226
227 /* set BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0
228 * LRP=0 IWL=00(16 bit) FORMAT=10(I2S format) */
229 wmcodec_write(AINTFCE, 0x42);
230
231 wmcodec_write(LOUTVOL, 0x0); /* headphone mute left */
232 wmcodec_write(ROUTVOL, 0x0); /* headphone mute right */
233
234
235 if(source_mic){
236 wmcodec_write(LINVOL, 0x80); /* line in mute left */
237 wmcodec_write(RINVOL, 0x80); /* line in mute right */
238
239
240 if (mic_boost) {
241 wmcodec_write(AAPCTRL, 0x5); /* INSEL=mic, MIC_BOOST=enable */
242 } else {
243 wmcodec_write(AAPCTRL, 0x4); /* INSEL=mic */
244 }
245 } else {
246 if (line_level == 0) {
247 wmcodec_write(LINVOL, 0x80);
248 wmcodec_write(RINVOL, 0x80);
249 } else {
250 wmcodec_write(LINVOL, line_level);
251 wmcodec_write(RINVOL, line_level);
252 }
253 wmcodec_write(AAPCTRL, 0xa); /* BY PASS, mute mic, INSEL=line in */
254 }
255
256 /* disable ADC high pass filter, mute dac */
257 wmcodec_write(DACCTRL, 0x9);
258
259 /* power on (PWR_OFF=0) */
260 if(source_mic){
261 /* CLKOUTPD OSCPD OUTPD DACPD LINEINPD */
262 wmcodec_write(PWRMGMT, 0x79);
263 } else {
264 wmcodec_write(PWRMGMT, 0x7a); /* MICPD */
265 }
266
267 codec_set_active(0x1);
224} 268}
225 269
226void audiohw_disable_recording(void) 270void audiohw_disable_recording(void)
227{ 271{
228 272 /* set DACMU=1 DEEMPH=0 */
273 wmcodec_write(DACCTRL, 0x8);
274
275 /* ACTIVE=0 */
276 codec_set_active(0x0);
277
278 /* line in mute left & right*/
279 wmcodec_write(LINVOL, 0x80);
280 wmcodec_write(RINVOL, 0x80);
281
282 /* set DACSEL=0, MUTEMIC=1 */
283 wmcodec_write(AAPCTRL, 0x2);
284
285 /* set POWEROFF=0 OUTPD=0 DACPD=1 */
286 wmcodec_write(PWRMGMT, 0x6f);
287
288 /* set POWEROFF=1 OUTPD=1 DACPD=1 */
289 wmcodec_write(PWRMGMT, 0xff);
229} 290}
230 291
231void audiohw_set_recvol(int left, int right, int type) 292void audiohw_set_recvol(int left, int right, int type)
diff --git a/firmware/drivers/wm8758.c b/firmware/drivers/wm8758.c
index 22bef73e45..9732d4f776 100644
--- a/firmware/drivers/wm8758.c
+++ b/firmware/drivers/wm8758.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Driver for WM8758 audio codec 10 * Driver for WM8758 audio codec - based on datasheet for WM8983
11 * 11 *
12 * Based on code from the ipodlinux project - http://ipodlinux.org/ 12 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in December 2005 13 * Adapted for Rockbox in December 2005
@@ -142,30 +142,11 @@ int audiohw_set_mixer_vol(int channel1, int channel2)
142void audiohw_set_bass(int value) 142void audiohw_set_bass(int value)
143{ 143{
144 (void)value; 144 (void)value;
145#if 0
146 /* Not yet implemented - this is the wm8975 code*/
147 int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0};
148
149 if ((value >= -6) && (value <= 9)) {
150 /* We use linear bass control with 130Hz cutoff */
151 wmcodec_write(BASSCTRL, regvalues[value+6]);
152 }
153#endif
154} 145}
155 146
156void audiohw_set_treble(int value) 147void audiohw_set_treble(int value)
157{ 148{
158 (void)value; 149 (void)value;
159#if 0
160 /* Not yet implemented - this is the wm8975 code*/
161 int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0};
162
163 if ((value >= -6) && (value <= 9)) {
164 /* We use a 8Khz cutoff */
165 wmcodec_write(TREBCTRL, regvalues[value+6]);
166 }
167#endif
168
169} 150}
170 151
171int audiohw_mute(int mute) 152int audiohw_mute(int mute)
@@ -224,11 +205,60 @@ void audiohw_set_sample_rate(int sampling_control)
224 205
225void audiohw_enable_recording(bool source_mic) 206void audiohw_enable_recording(bool source_mic)
226{ 207{
227 (void)source_mic; 208 (void)source_mic; /* We only have a line-in (I think) */
209
210 /* reset the I2S controller into known state */
211 i2s_reset();
212
213 wmcodec_write(RESET, 0x1ff); /*Reset*/
214
215 wmcodec_write(PWRMGMT1, 0x2b);
216 wmcodec_write(PWRMGMT2, 0x18f); /* Enable ADC - 0x0c enables left/right PGA input, and 0x03 turns on power to the ADCs */
217 wmcodec_write(PWRMGMT3, 0x6f);
218
219 wmcodec_write(AINTFCE, 0x10);
220 wmcodec_write(CLKCTRL, 0x49);
221
222 wmcodec_write(OUTCTRL, 1);
223
224 /* The iPod can handle multiple frequencies, but fix at 44.1KHz
225 for now */
226 wmcodec_set_sample_rate(WM8758_44100HZ);
227
228 wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */
229
230 /* Set L2/R2_2BOOSTVOL to 0db (bits 4-6) */
231 /* 000 = disabled
232 001 = -12dB
233 010 = -9dB
234 011 = -6dB
235 100 = -3dB
236 101 = 0dB
237 110 = 3dB
238 111 = 6dB
239 */
240 wmcodec_write(LADCBOOST,0x50);
241 wmcodec_write(RADCBOOST,0x50);
242
243 /* Set L/R input PGA Volume to 0db */
244 // wm8758_write(LINPGAVOL,0x3f);
245 // wm8758_write(RINPGAVOL,0x13f);
246
247 /* Enable monitoring */
248 wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/
249 wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/
250
251 wmcodec_mute(0);
228} 252}
229 253
230void audiohw_disable_recording(void) { 254void audiohw_disable_recording(void) {
255 wmcodec_mute(1);
256
257 wmcodec_write(PWRMGMT3, 0x0);
231 258
259 wmcodec_write(PWRMGMT1, 0x0);
260
261 wmcodec_write(PWRMGMT2, 0x40);
232} 262}
233 263
234void audiohw_set_recvol(int left, int right, int type) { 264void audiohw_set_recvol(int left, int right, int type) {
diff --git a/firmware/drivers/wm8975.c b/firmware/drivers/wm8975.c
index d2b1fa64b2..011d771a13 100644
--- a/firmware/drivers/wm8975.c
+++ b/firmware/drivers/wm8975.c
@@ -224,13 +224,80 @@ void audiohw_set_sample_rate(int sampling_control) {
224 224
225} 225}
226 226
227void audiohw_enable_recording(bool source_mic) { 227void audiohw_enable_recording(bool source_mic)
228{
229 (void)source_mic;
228 230
229 (void)source_mic; 231 /* reset the I2S controller into known state */
230} 232 i2s_reset();
233
234 /*
235 * 1. Switch on power supplies.
236 * By default the WM8750L is in Standby Mode, the DAC is
237 * digitally muted and the Audio Interface, Line outputs
238 * and Headphone outputs are all OFF (DACMU = 1 Power
239 * Management registers 1 and 2 are all zeros).
240 */
241 wmcodec_write(0x0f, 0x1ff);
242 wmcodec_write(0x0f, 0x000);
243
244 /* 2. Enable Vmid and VREF. */
245 wmcodec_write(0x19, 0xc0); /*Pwr Mgmt(1)*/
246
247 /* 3. Enable ADCs as required. */
248 wmcodec_write(0x19, 0xcc); /*Pwr Mgmt(1)*/
249 wmcodec_write(0x1a, 0x180); /*Pwr Mgmt(2)*/
250
251 /* 4. Enable line and / or headphone output buffers as required. */
252 wmcodec_write(0x19, 0xfc); /*Pwr Mgmt(1)*/
253
254 /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */
255 /* IWL=00(16 bit) FORMAT=10(I2S format) */
256 wmcodec_write(0x07, 0x42);
257
258 /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */
259 wmcodec_set_sample_rate(WM8975_44100HZ);
260
261 /* unmute inputs */
262 wmcodec_write(0x00, 0x17); /* LINVOL (def 0dB) */
263 wmcodec_write(0x01, 0x117); /* RINVOL (def 0dB) */
264
265 wmcodec_write(0x15, 0x1d7); /* LADCVOL max vol x was ff */
266 wmcodec_write(0x16, 0x1d7); /* RADCVOL max vol x was ff */
267
268 if (source_mic) {
269 /* VSEL=10(def) DATSEL=10 (use right ADC only) */
270 wmcodec_write(0x17, 0xc8); /* Additional control(1) */
231 271
272 /* VROI=1 (sets output resistance to 40kohms) */
273 wmcodec_write(0x1b, 0x40); /* Additional control(3) */
274
275 /* LINSEL=1 (LINPUT2) LMICBOOST=10 (20dB boost) */
276 wmcodec_write(0x20, 0x60); /* ADCL signal path */
277 wmcodec_write(0x21, 0x60); /* ADCR signal path */
278 } else {
279 /* VSEL=10(def) DATSEL=00 (left->left, right->right) */
280 wmcodec_write(0x17, 0xc0); /* Additional control(1) */
281
282 /* VROI=1 (sets output resistance to 40kohms) */
283 wmcodec_write(0x1b, 0x40); /* Additional control(3) */
284
285 /* LINSEL=0 (LINPUT1) LMICBOOST=00 (bypass boost) */
286 wmcodec_write(0x20, 0x00); /* ADCL signal path */
287 /* RINSEL=0 (RINPUT1) RMICBOOST=00 (bypass boost) */
288 wmcodec_write(0x21, 0x00); /* ADCR signal path */
289 }
290}
291
232void audiohw_disable_recording(void) { 292void audiohw_disable_recording(void) {
293 /* 1. Set DACMU = 1 to soft-mute the audio DACs. */
294 wmcodec_write(0x05, 0x8);
233 295
296 /* 2. Disable all output buffers. */
297 wmcodec_write(0x1a, 0x0); /*Pwr Mgmt(2)*/
298
299 /* 3. Switch off the power supplies. */
300 wmcodec_write(0x19, 0x0); /*Pwr Mgmt(1)*/
234} 301}
235 302
236void audiohw_set_recvol(int left, int right, int type) { 303void audiohw_set_recvol(int left, int right, int type) {
diff --git a/firmware/export/config-h10.h b/firmware/export/config-h10.h
index 7ea3c2dae6..0b17920736 100644
--- a/firmware/export/config-h10.h
+++ b/firmware/export/config-h10.h
@@ -8,7 +8,13 @@
8#define MODEL_NUMBER 13 8#define MODEL_NUMBER 13
9 9
10/* define this if you have recording possibility */ 10/* define this if you have recording possibility */
11/*#define HAVE_RECORDING 1*/ /* TODO: add support for this */ 11#define HAVE_RECORDING 1
12
13/* define the bitmask of hardware sample rates */
14#define HW_SAMPR_CAPS (SAMPR_CAP_44)
15
16/* define the bitmask of recording sample rates */
17#define REC_SAMPR_CAPS (SAMPR_CAP_44)
12 18
13/* define this if you have a bitmap LCD display */ 19/* define this if you have a bitmap LCD display */
14#define HAVE_LCD_BITMAP 1 20#define HAVE_LCD_BITMAP 1
diff --git a/firmware/export/config-h10_5gb.h b/firmware/export/config-h10_5gb.h
index 34b1d14d77..534c4a455f 100644
--- a/firmware/export/config-h10_5gb.h
+++ b/firmware/export/config-h10_5gb.h
@@ -8,7 +8,13 @@
8#define MODEL_NUMBER 14 8#define MODEL_NUMBER 14
9 9
10/* define this if you have recording possibility */ 10/* define this if you have recording possibility */
11/*#define HAVE_RECORDING 1*/ /* TODO: add support for this */ 11#define HAVE_RECORDING 1
12
13/* define the bitmask of hardware sample rates */
14#define HW_SAMPR_CAPS (SAMPR_CAP_44)
15
16/* define the bitmask of recording sample rates */
17#define REC_SAMPR_CAPS (SAMPR_CAP_44)
12 18
13/* define this if you have a bitmap LCD display */ 19/* define this if you have a bitmap LCD display */
14#define HAVE_LCD_BITMAP 1 20#define HAVE_LCD_BITMAP 1
diff --git a/firmware/export/config-ipod4g.h b/firmware/export/config-ipod4g.h
index bf8d5359f8..142a2ebabb 100644
--- a/firmware/export/config-ipod4g.h
+++ b/firmware/export/config-ipod4g.h
@@ -9,7 +9,13 @@
9#define MODEL_NUMBER 8 9#define MODEL_NUMBER 8
10 10
11/* define this if you have recording possibility */ 11/* define this if you have recording possibility */
12/*#define HAVE_RECORDING 1*/ 12#define HAVE_RECORDING 1
13
14/* define the bitmask of hardware sample rates */
15#define HW_SAMPR_CAPS (SAMPR_CAP_44)
16
17/* define the bitmask of recording sample rates */
18#define REC_SAMPR_CAPS (SAMPR_CAP_44)
13 19
14/* define this if you have a bitmap LCD display */ 20/* define this if you have a bitmap LCD display */
15#define HAVE_LCD_BITMAP 1 21#define HAVE_LCD_BITMAP 1
diff --git a/firmware/export/config-ipodcolor.h b/firmware/export/config-ipodcolor.h
index de06b223e5..af2a89cf6f 100644
--- a/firmware/export/config-ipodcolor.h
+++ b/firmware/export/config-ipodcolor.h
@@ -9,7 +9,13 @@
9#define MODEL_NUMBER 3 9#define MODEL_NUMBER 3
10 10
11/* define this if you have recording possibility */ 11/* define this if you have recording possibility */
12/*#define HAVE_RECORDING 1*/ 12#define HAVE_RECORDING 1
13
14/* define the bitmask of hardware sample rates */
15#define HW_SAMPR_CAPS (SAMPR_CAP_44)
16
17/* define the bitmask of recording sample rates */
18#define REC_SAMPR_CAPS (SAMPR_CAP_44)
13 19
14/* define this if you have a bitmap LCD display */ 20/* define this if you have a bitmap LCD display */
15#define HAVE_LCD_BITMAP 1 21#define HAVE_LCD_BITMAP 1
diff --git a/firmware/export/config-ipodnano.h b/firmware/export/config-ipodnano.h
index 3dd0575b1b..f72603a2da 100644
--- a/firmware/export/config-ipodnano.h
+++ b/firmware/export/config-ipodnano.h
@@ -9,7 +9,13 @@
9#define MODEL_NUMBER 4 9#define MODEL_NUMBER 4
10 10
11/* define this if you have recording possibility */ 11/* define this if you have recording possibility */
12/*#define HAVE_RECORDING 1*/ 12#define HAVE_RECORDING 1
13
14/* define the bitmask of hardware sample rates */
15#define HW_SAMPR_CAPS (SAMPR_CAP_44)
16
17/* define the bitmask of recording sample rates */
18#define REC_SAMPR_CAPS (SAMPR_CAP_44)
13 19
14/* define this if you have a bitmap LCD display */ 20/* define this if you have a bitmap LCD display */
15#define HAVE_LCD_BITMAP 1 21#define HAVE_LCD_BITMAP 1
diff --git a/firmware/export/config-ipodvideo.h b/firmware/export/config-ipodvideo.h
index b2b56158f3..fa78c5c7ee 100644
--- a/firmware/export/config-ipodvideo.h
+++ b/firmware/export/config-ipodvideo.h
@@ -9,7 +9,13 @@
9#define MODEL_NUMBER 5 9#define MODEL_NUMBER 5
10 10
11/* define this if you have recording possibility */ 11/* define this if you have recording possibility */
12/*#define HAVE_RECORDING 1*/ 12#define HAVE_RECORDING 1
13
14/* define the bitmask of hardware sample rates */
15#define HW_SAMPR_CAPS (SAMPR_CAP_44)
16
17/* define the bitmask of recording sample rates */
18#define REC_SAMPR_CAPS (SAMPR_CAP_44)
13 19
14/* define this if you have a bitmap LCD display */ 20/* define this if you have a bitmap LCD display */
15#define HAVE_LCD_BITMAP 1 21#define HAVE_LCD_BITMAP 1
diff --git a/firmware/export/sound.h b/firmware/export/sound.h
index 2cf2ad3136..3ad74c4859 100644
--- a/firmware/export/sound.h
+++ b/firmware/export/sound.h
@@ -48,7 +48,8 @@ enum {
48 SOUND_MDB_ENABLE, 48 SOUND_MDB_ENABLE,
49 SOUND_SUPERBASS, 49 SOUND_SUPERBASS,
50#endif 50#endif
51#if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320) 51#if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320)\
52 || defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8731)
52 SOUND_LEFT_GAIN, 53 SOUND_LEFT_GAIN,
53 SOUND_RIGHT_GAIN, 54 SOUND_RIGHT_GAIN,
54 SOUND_MIC_GAIN, 55 SOUND_MIC_GAIN,
diff --git a/firmware/export/system.h b/firmware/export/system.h
index 2523a72fb3..3db38c9c7b 100644
--- a/firmware/export/system.h
+++ b/firmware/export/system.h
@@ -314,8 +314,11 @@ static inline int set_irq_level(int level)
314 return (cpsr >> 7) & 1; 314 return (cpsr >> 7) & 1;
315} 315}
316 316
317static inline void enable_fiq(void) 317static inline void enable_fiq(void(*fiq_handler)(void))
318{ 318{
319 /* Install the FIQ handler */
320 *((unsigned int*)(15*4)) = (unsigned int)fiq_handler;
321
319 /* Clear FIQ disable bit */ 322 /* Clear FIQ disable bit */
320 asm volatile ( 323 asm volatile (
321 "mrs r0, cpsr \n"\ 324 "mrs r0, cpsr \n"\
diff --git a/firmware/export/wm8731l.h b/firmware/export/wm8731l.h
index b6fa13f6cb..5ef6d694e5 100644
--- a/firmware/export/wm8731l.h
+++ b/firmware/export/wm8731l.h
@@ -49,6 +49,7 @@ extern void audiohw_set_monitor(int enable);
49#define RINVOL 0x01 49#define RINVOL 0x01
50#define LOUTVOL 0x02 50#define LOUTVOL 0x02
51#define ROUTVOL 0x03 51#define ROUTVOL 0x03
52#define AAPCTRL 0x04 /* Analog audio path control */
52#define DACCTRL 0x05 53#define DACCTRL 0x05
53#define PWRMGMT 0x06 54#define PWRMGMT 0x06
54#define AINTFCE 0x07 55#define AINTFCE 0x07
diff --git a/firmware/export/wm8758.h b/firmware/export/wm8758.h
index 20b26dc11f..5715f100da 100644
--- a/firmware/export/wm8758.h
+++ b/firmware/export/wm8758.h
@@ -55,6 +55,11 @@ extern void audiohw_set_equalizer_band(int band, int freq, int bw, int gain);
55#define CLKCTRL 0x06 55#define CLKCTRL 0x06
56#define SRATECTRL 0x07 56#define SRATECTRL 0x07
57#define DACCTRL 0x0a 57#define DACCTRL 0x0a
58#define INCTRL 0x2c
59#define LINPGAVOL 0x2d
60#define RINPGAVOL 0x2e
61#define LADCBOOST 0x2f
62#define RADCBOOST 0x30
58#define OUTCTRL 0x31 63#define OUTCTRL 0x31
59#define LOUTMIX 0x32 64#define LOUTMIX 0x32
60#define ROUTMIX 0x33 65#define ROUTMIX 0x33
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c
index 46a458fa8a..92a4c3e5c7 100644
--- a/firmware/pcm_playback.c
+++ b/firmware/pcm_playback.c
@@ -98,326 +98,6 @@ size_t pcm_get_bytes_waiting(void)
98 return 0; 98 return 0;
99} 99}
100 100
101#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
102 || defined(HAVE_WM8731) || defined(HAVE_WM8721) \
103 || defined(HAVE_PP5024_CODEC)
104
105/* We need to unify this code with the uda1380 code as much as possible, but
106 we will keep it separate during early development.
107*/
108
109#if CONFIG_CPU == PP5020
110#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x3f0000) >> 16)
111#elif CONFIG_CPU == PP5002
112#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x7800000) >> 23)
113#elif CONFIG_CPU == PP5024
114#define FIFO_FREE_COUNT 4 /* TODO: make this sensible */
115#endif
116
117static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */
118
119/* NOTE: The order of these two variables is important if you use the iPod
120 assembler optimised fiq handler, so don't change it. */
121unsigned short* p IBSS_ATTR;
122size_t p_size IBSS_ATTR;
123
124void pcm_play_dma_start(const void *addr, size_t size)
125{
126 p=(unsigned short*)addr;
127 p_size=size;
128
129 pcm_playing = true;
130
131#if CONFIG_CPU == PP5020
132 /* setup I2S interrupt for FIQ */
133 outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
134 outl(I2S_MASK, 0x60004024);
135#elif CONFIG_CPU == PP5024
136#else
137 /* setup I2S interrupt for FIQ */
138 outl(inl(0xcf00102c) | DMA_OUT_MASK, 0xcf00102c);
139 outl(DMA_OUT_MASK, 0xcf001024);
140#endif
141
142 /* Clear the FIQ disable bit in cpsr_c */
143 enable_fiq();
144
145 /* Enable playback FIFO */
146#if CONFIG_CPU == PP5020
147 IISCONFIG |= 0x20000000;
148#elif CONFIG_CPU == PP5002
149 IISCONFIG |= 0x4;
150#endif
151
152 /* Fill the FIFO - we assume there are enough bytes in the pcm buffer to
153 fill the 32-byte FIFO. */
154 while (p_size > 0) {
155 if (FIFO_FREE_COUNT < 2) {
156 /* Enable interrupt */
157#if CONFIG_CPU == PP5020
158 IISCONFIG |= 0x2;
159#elif CONFIG_CPU == PP5002
160 IISFIFO_CFG |= (1<<9);
161#endif
162 return;
163 }
164
165 IISFIFO_WR = (*(p++))<<16;
166 IISFIFO_WR = (*(p++))<<16;
167 p_size-=4;
168 }
169}
170
171/* Stops the DMA transfer and interrupt */
172void pcm_play_dma_stop(void)
173{
174 pcm_playing = false;
175
176#if CONFIG_CPU == PP5020
177
178 /* Disable playback FIFO */
179 IISCONFIG &= ~0x20000000;
180
181 /* Disable the interrupt */
182 IISCONFIG &= ~0x2;
183
184#elif CONFIG_CPU == PP5002
185
186 /* Disable playback FIFO */
187 IISCONFIG &= ~0x4;
188
189 /* Disable the interrupt */
190 IISFIFO_CFG &= ~(1<<9);
191#endif
192
193 disable_fiq();
194}
195
196void pcm_play_pause_pause(void)
197{
198#if CONFIG_CPU == PP5020
199 /* Disable the interrupt */
200 IISCONFIG &= ~0x2;
201 /* Disable playback FIFO */
202 IISCONFIG &= ~0x20000000;
203#elif CONFIG_CPU == PP5002
204 /* Disable the interrupt */
205 IISFIFO_CFG &= ~(1<<9);
206 /* Disable playback FIFO */
207 IISCONFIG &= ~0x4;
208#endif
209 disable_fiq();
210}
211
212void pcm_play_pause_unpause(void)
213{
214 /* Enable the FIFO and fill it */
215
216 enable_fiq();
217
218 /* Enable playback FIFO */
219#if CONFIG_CPU == PP5020
220 IISCONFIG |= 0x20000000;
221#elif CONFIG_CPU == PP5002
222 IISCONFIG |= 0x4;
223#endif
224
225 /* Fill the FIFO - we assume there are enough bytes in the
226 pcm buffer to fill the 32-byte FIFO. */
227 while (p_size > 0) {
228 if (FIFO_FREE_COUNT < 2) {
229 /* Enable interrupt */
230#if CONFIG_CPU == PP5020
231 IISCONFIG |= 0x2;
232#elif CONFIG_CPU == PP5002
233 IISFIFO_CFG |= (1<<9);
234#endif
235 return;
236 }
237
238 IISFIFO_WR = (*(p++))<<16;
239 IISFIFO_WR = (*(p++))<<16;
240 p_size-=4;
241 }
242}
243
244void pcm_set_frequency(unsigned int frequency)
245{
246 (void)frequency;
247 pcm_freq = HW_SAMPR_DEFAULT;
248}
249
250size_t pcm_get_bytes_waiting(void)
251{
252 return p_size;
253}
254
255/* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode
256 has registers r8-r14 banked, and so does not need to be saved. This routine
257 uses only these registers, and so will never touch the stack unless it
258 actually needs to do so when calling pcm_callback_for_more. C version is
259 still included below for reference.
260 */
261#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002
262void fiq(void) ICODE_ATTR __attribute__((naked));
263void fiq(void)
264{
265 /* r12 contains IISCONFIG address (set in crt0.S to minimise code in actual
266 * FIQ handler. r11 contains address of p (also set in crt0.S). Most other
267 * addresses we need are generated by using offsets with these two.
268 * r12 + 0x40 is IISFIFO_WR, and r12 + 0x0c is IISFIFO_CFG.
269 * r8 and r9 contains local copies of p_size and p respectively.
270 * r10 is a working register.
271 */
272 asm volatile (
273#if CONFIG_CPU == PP5002
274 "ldr r10, =0xcf001040 \n\t" /* Some magic from iPodLinux */
275 "ldr r10, [r10] \n\t"
276 "ldr r10, [r12, #0x1c]\n\t"
277 "bic r10, r10, #0x200 \n\t" /* clear interrupt */
278 "str r10, [r12, #0x1c]\n\t"
279#else
280 "ldr r10, [r12] \n\t"
281 "bic r10, r10, #0x2 \n\t" /* clear interrupt */
282 "str r10, [r12] \n\t"
283#endif
284 "ldr r8, [r11, #4] \n\t" /* r8 = p_size */
285 "ldr r9, [r11] \n\t" /* r9 = p */
286 ".loop: \n\t"
287 "cmp r8, #0 \n\t" /* is p_size 0? */
288 "beq .more_data \n\t" /* if so, ask pcmbuf for more data */
289 ".fifo_loop: \n\t"
290#if CONFIG_CPU == PP5002
291 "ldr r10, [r12, #0x1c]\n\t" /* read IISFIFO_CFG to check FIFO status */
292 "and r10, r10, #0x7800000\n\t"
293 "cmp r10, #0x800000 \n\t"
294#else
295 "ldr r10, [r12, #0x0c]\n\t" /* read IISFIFO_CFG to check FIFO status */
296 "and r10, r10, #0x3f0000\n\t"
297 "cmp r10, #0x10000 \n\t"
298#endif
299 "bls .fifo_full \n\t" /* FIFO full, exit */
300 "ldr r10, [r9], #4 \n\t" /* load two samples */
301 "mov r10, r10, ror #16\n\t" /* put left sample at the top bits */
302 "str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */
303 "mov r10, r10, lsl #16\n\t" /* shift lower sample up */
304 "str r10, [r12, #0x40]\n\t" /* then write it */
305 "subs r8, r8, #4 \n\t" /* check if we have more samples */
306 "bne .fifo_loop \n\t" /* yes, continue */
307 ".more_data: \n\t"
308 "stmdb sp!, { r0-r3, r12, lr}\n\t" /* stack scratch regs and lr */
309 "mov r0, r11 \n\t" /* r0 = &p */
310 "add r1, r11, #4 \n\t" /* r1 = &p_size */
311 "str r9, [r0] \n\t" /* save internal copies of variables back */
312 "str r8, [r1] \n\t"
313 "ldr r2, =pcm_callback_for_more\n\t"
314 "ldr r2, [r2] \n\t" /* get callback address */
315 "cmp r2, #0 \n\t" /* check for null pointer */
316 "movne lr, pc \n\t" /* call pcm_callback_for_more */
317 "bxne r2 \n\t"
318 "ldmia sp!, { r0-r3, r12, lr}\n\t"
319 "ldr r8, [r11, #4] \n\t" /* reload p_size and p */
320 "ldr r9, [r11] \n\t"
321 "cmp r8, #0 \n\t" /* did we actually get more data? */
322 "bne .loop \n\t" /* yes, continue to try feeding FIFO */
323 ".dma_stop: \n\t" /* no more data, do dma_stop() and exit */
324 "ldr r10, =pcm_playing\n\t"
325 "strb r8, [r10] \n\t" /* pcm_playing = false (r8=0, look above) */
326 "ldr r10, [r12] \n\t"
327#if CONFIG_CPU == PP5002
328 "bic r10, r10, #0x4\n\t" /* disable playback FIFO */
329 "str r10, [r12] \n\t"
330 "ldr r10, [r12, #0x1c] \n\t"
331 "bic r10, r10, #0x200 \n\t" /* clear interrupt */
332 "str r10, [r12, #0x1c] \n\t"
333#else
334 "bic r10, r10, #0x20000002\n\t" /* disable playback FIFO and IRQ */
335 "str r10, [r12] \n\t"
336#endif
337 "mrs r10, cpsr \n\t"
338 "orr r10, r10, #0x40 \n\t" /* disable FIQ */
339 "msr cpsr_c, r10 \n\t"
340 ".exit: \n\t"
341 "str r8, [r11, #4] \n\t"
342 "str r9, [r11] \n\t"
343 "subs pc, lr, #4 \n\t" /* FIQ specific return sequence */
344 ".fifo_full: \n\t" /* enable IRQ and exit */
345#if CONFIG_CPU == PP5002
346 "ldr r10, [r12, #0x1c]\n\t"
347 "orr r10, r10, #0x200 \n\t" /* set interrupt */
348 "str r10, [r12, #0x1c]\n\t"
349#else
350 "ldr r10, [r12] \n\t"
351 "orr r10, r10, #0x2 \n\t" /* set interrupt */
352 "str r10, [r12] \n\t"
353#endif
354 "b .exit \n\t"
355 );
356}
357#else /* !(CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002) */
358void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
359void fiq(void)
360{
361 /* Clear interrupt */
362#if CONFIG_CPU == PP5020
363 IISCONFIG &= ~0x2;
364#elif CONFIG_CPU == PP5002
365 inl(0xcf001040);
366 IISFIFO_CFG &= ~(1<<9);
367#endif
368
369 do {
370 while (p_size) {
371 if (FIFO_FREE_COUNT < 2) {
372 /* Enable interrupt */
373#if CONFIG_CPU == PP5020
374 IISCONFIG |= 0x2;
375#elif CONFIG_CPU == PP5002
376 IISFIFO_CFG |= (1<<9);
377#endif
378 return;
379 }
380
381 IISFIFO_WR = (*(p++))<<16;
382 IISFIFO_WR = (*(p++))<<16;
383 p_size-=4;
384 }
385
386 /* p is empty, get some more data */
387 if (pcm_callback_for_more) {
388 pcm_callback_for_more((unsigned char**)&p,&p_size);
389 }
390 } while (p_size);
391
392 /* No more data, so disable the FIFO/FIQ */
393 pcm_play_dma_stop();
394}
395#endif /* CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 */
396
397#ifdef HAVE_PP5024_CODEC
398void pcm_init(void)
399{
400}
401#else
402void pcm_init(void)
403{
404 pcm_playing = false;
405 pcm_paused = false;
406 pcm_callback_for_more = NULL;
407
408 /* Initialize default register values. */
409 audiohw_init();
410
411 /* Power on */
412 audiohw_enable_output(true);
413
414 /* Unmute the master channel (DAC should be at zero point now). */
415 audiohw_mute(false);
416
417 /* Call pcm_play_dma_stop to initialize everything. */
418 pcm_play_dma_stop();
419}
420#endif /* HAVE_PP5024_CODEC */
421#elif (CONFIG_CPU == PNX0101) 101#elif (CONFIG_CPU == PNX0101)
422 102
423#define DMA_BUF_SAMPLES 0x100 103#define DMA_BUF_SAMPLES 0x100
@@ -608,7 +288,7 @@ void pcm_mute(bool mute)
608 if (mute) 288 if (mute)
609 sleep(HZ/16); 289 sleep(HZ/16);
610} 290}
611 291#if !defined(CPU_PP)
612/* 292/*
613 * This function goes directly into the DMA buffer to calculate the left and 293 * This function goes directly into the DMA buffer to calculate the left and
614 * right peak values. To avoid missing peaks it tries to look forward two full 294 * right peak values. To avoid missing peaks it tries to look forward two full
@@ -632,9 +312,7 @@ void pcm_calculate_peaks(int *left, int *right)
632 short *addr; 312 short *addr;
633 short *end; 313 short *end;
634 { 314 {
635#if defined(HAVE_WM8975) || defined(HAVE_WM8758) \ 315#if CONFIG_CPU == PNX0101
636 || defined(HAVE_WM8731) || defined(HAVE_WM8721) \
637 || (CONFIG_CPU == PNX0101) || defined(HAVE_PP5024_CODEC)
638 size_t samples = p_size / 4; 316 size_t samples = p_size / 4;
639 addr = p; 317 addr = p;
640#endif 318#endif
@@ -690,7 +368,7 @@ void pcm_calculate_peaks(int *left, int *right)
690 } 368 }
691#endif 369#endif
692} 370}
693 371#endif
694#endif /* CPU_COLDFIRE */ 372#endif /* CPU_COLDFIRE */
695 373
696/**************************************************************************** 374/****************************************************************************
diff --git a/firmware/sound.c b/firmware/sound.c
index 09fa3dac94..c3679d41f2 100644
--- a/firmware/sound.c
+++ b/firmware/sound.c
@@ -112,7 +112,19 @@ static const struct sound_settings_info sound_settings_table[] = {
112 [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23, NULL}, 112 [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23, NULL},
113 [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23, NULL}, 113 [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23, NULL},
114 [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 1, NULL}, 114 [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 1, NULL},
115 #endif 115#elif defined(HAVE_WM8975)
116 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
117 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
118 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16, NULL},
119#elif defined(HAVE_WM8758)
120 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
121 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
122 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16, NULL},
123#elif defined(HAVE_WM8731)
124 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
125 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
126 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16, NULL},
127#endif
116}; 128};
117 129
118const char *sound_unit(int setting) 130const char *sound_unit(int setting)
diff --git a/firmware/target/arm/audio-pp.c b/firmware/target/arm/audio-pp.c
new file mode 100644
index 0000000000..c08db8a88a
--- /dev/null
+++ b/firmware/target/arm/audio-pp.c
@@ -0,0 +1,84 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 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
24void audio_set_output_source(int source)
25{
26 if ((unsigned)source >= AUDIO_NUM_SOURCES)
27 source = AUDIO_SRC_PLAYBACK;
28} /* audio_set_output_source */
29
30void audio_set_source(int source, unsigned flags)
31{
32 /* Prevent pops from unneeded switching */
33 static int last_source = AUDIO_SRC_PLAYBACK;
34 bool recording = flags & SRCF_RECORDING;
35 static bool last_recording = false;
36
37 switch (source)
38 {
39 default: /* playback - no recording */
40 source = AUDIO_SRC_PLAYBACK;
41 case AUDIO_SRC_PLAYBACK:
42 if (source != last_source)
43 {
44 audiohw_disable_recording();
45 audiohw_set_monitor(false);
46 }
47 break;
48
49 case AUDIO_SRC_MIC: /* recording only */
50 if (source != last_source)
51 {
52 audiohw_enable_recording(true); /* source mic */
53 audiohw_set_monitor(false);
54 }
55 break;
56
57 case AUDIO_SRC_LINEIN: /* recording only */
58 if (source != last_source)
59 {
60 audiohw_enable_recording(false); /* source line */
61 audiohw_set_monitor(false);
62 }
63 break;
64#ifdef CONFIG_TUNER
65 case AUDIO_SRC_FMRADIO: /* recording and playback */
66 if (!recording)
67 audiohw_set_recvol(0, 0, AUDIO_GAIN_LINEIN);
68
69 if (source == last_source && recording == last_recording)
70 break;
71
72 last_recording = recording;
73
74 /* I2S recording and playback */
75 audiohw_enable_recording(false); /* source line */
76 audiohw_set_monitor(!recording);
77 break;
78#endif
79 } /* end switch */
80
81 last_source = source;
82} /* audio_set_source */
83
84
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c
new file mode 100644
index 0000000000..d9a3b6d7d7
--- /dev/null
+++ b/firmware/target/arm/pcm-pp.c
@@ -0,0 +1,578 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 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 <stdlib.h>
20#include "system.h"
21#include "kernel.h"
22#include "logf.h"
23#include "audio.h"
24#if defined(HAVE_WM8975)
25#include "wm8975.h"
26#elif defined(HAVE_WM8758)
27#include "wm8758.h"
28#elif defined(HAVE_WM8731)
29#include "wm8731l.h"
30#endif
31
32
33
34/* peaks */
35static int play_peak_left, play_peak_right;
36static unsigned long *rec_peak_addr;
37static int rec_peak_left, rec_peak_right;
38
39/** DMA **/
40#if CONFIG_CPU == PP5020
41#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x3f000000) >> 24)
42#elif CONFIG_CPU == PP5002
43#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x7800000) >> 23)
44#elif CONFIG_CPU == PP5024
45#define FIFO_FREE_COUNT 4 /* TODO: make this sensible */
46#endif
47
48/****************************************************************************
49 ** Playback DMA transfer
50 **/
51static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */
52
53/* NOTE: The order of these two variables is important if you use the iPod
54 assembler optimised fiq handler, so don't change it. */
55unsigned short* p IBSS_ATTR;
56size_t p_size IBSS_ATTR;
57
58/* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode
59 has registers r8-r14 banked, and so does not need to be saved. This routine
60 uses only these registers, and so will never touch the stack unless it
61 actually needs to do so when calling pcm_callback_for_more. C version is
62 still included below for reference.
63 */
64#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002
65void fiq(void) ICODE_ATTR __attribute__((naked));
66void fiq(void)
67{
68 /* r12 contains IISCONFIG address (set in crt0.S to minimise code in actual
69 * FIQ handler. r11 contains address of p (also set in crt0.S). Most other
70 * addresses we need are generated by using offsets with these two.
71 * r12 + 0x40 is IISFIFO_WR, and r12 + 0x0c is IISFIFO_CFG.
72 * r8 and r9 contains local copies of p_size and p respectively.
73 * r10 is a working register.
74 */
75 asm volatile (
76#if CONFIG_CPU == PP5002
77 "ldr r10, =0xcf001040 \n\t" /* Some magic from iPodLinux */
78 "ldr r10, [r10] \n\t"
79 "ldr r10, [r12, #0x1c]\n\t"
80 "bic r10, r10, #0x200 \n\t" /* clear interrupt */
81 "str r10, [r12, #0x1c]\n\t"
82#else
83 "ldr r10, [r12] \n\t"
84 "bic r10, r10, #0x2 \n\t" /* clear interrupt */
85 "str r10, [r12] \n\t"
86#endif
87 "ldr r8, [r11, #4] \n\t" /* r8 = p_size */
88 "ldr r9, [r11] \n\t" /* r9 = p */
89 ".loop: \n\t"
90 "cmp r8, #0 \n\t" /* is p_size 0? */
91 "beq .more_data \n\t" /* if so, ask pcmbuf for more data */
92 ".fifo_loop: \n\t"
93#if CONFIG_CPU == PP5002
94 "ldr r10, [r12, #0x1c]\n\t" /* read IISFIFO_CFG to check FIFO status */
95 "and r10, r10, #0x7800000\n\t"
96 "cmp r10, #0x800000 \n\t"
97#else
98 "ldr r10, [r12, #0x0c]\n\t" /* read IISFIFO_CFG to check FIFO status */
99 "and r10, r10, #0x3f0000\n\t"
100 "cmp r10, #0x10000 \n\t"
101#endif
102 "bls .fifo_full \n\t" /* FIFO full, exit */
103 "ldr r10, [r9], #4 \n\t" /* load two samples */
104 "mov r10, r10, ror #16\n\t" /* put left sample at the top bits */
105 "str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */
106 "mov r10, r10, lsl #16\n\t" /* shift lower sample up */
107 "str r10, [r12, #0x40]\n\t" /* then write it */
108 "subs r8, r8, #4 \n\t" /* check if we have more samples */
109 "bne .fifo_loop \n\t" /* yes, continue */
110 ".more_data: \n\t"
111 "stmdb sp!, { r0-r3, r12, lr}\n\t" /* stack scratch regs and lr */
112 "mov r0, r11 \n\t" /* r0 = &p */
113 "add r1, r11, #4 \n\t" /* r1 = &p_size */
114 "str r9, [r0] \n\t" /* save internal copies of variables back */
115 "str r8, [r1] \n\t"
116 "ldr r2, =pcm_callback_for_more\n\t"
117 "ldr r2, [r2] \n\t" /* get callback address */
118 "cmp r2, #0 \n\t" /* check for null pointer */
119 "movne lr, pc \n\t" /* call pcm_callback_for_more */
120 "bxne r2 \n\t"
121 "ldmia sp!, { r0-r3, r12, lr}\n\t"
122 "ldr r8, [r11, #4] \n\t" /* reload p_size and p */
123 "ldr r9, [r11] \n\t"
124 "cmp r8, #0 \n\t" /* did we actually get more data? */
125 "bne .loop \n\t" /* yes, continue to try feeding FIFO */
126 ".dma_stop: \n\t" /* no more data, do dma_stop() and exit */
127 "ldr r10, =pcm_playing\n\t"
128 "strb r8, [r10] \n\t" /* pcm_playing = false (r8=0, look above) */
129 "ldr r10, [r12] \n\t"
130#if CONFIG_CPU == PP5002
131 "bic r10, r10, #0x4\n\t" /* disable playback FIFO */
132 "str r10, [r12] \n\t"
133 "ldr r10, [r12, #0x1c] \n\t"
134 "bic r10, r10, #0x200 \n\t" /* clear interrupt */
135 "str r10, [r12, #0x1c] \n\t"
136#else
137 "bic r10, r10, #0x20000002\n\t" /* disable playback FIFO and IRQ */
138 "str r10, [r12] \n\t"
139#endif
140 "mrs r10, cpsr \n\t"
141 "orr r10, r10, #0x40 \n\t" /* disable FIQ */
142 "msr cpsr_c, r10 \n\t"
143 ".exit: \n\t"
144 "str r8, [r11, #4] \n\t"
145 "str r9, [r11] \n\t"
146 "subs pc, lr, #4 \n\t" /* FIQ specific return sequence */
147 ".fifo_full: \n\t" /* enable IRQ and exit */
148#if CONFIG_CPU == PP5002
149 "ldr r10, [r12, #0x1c]\n\t"
150 "orr r10, r10, #0x200 \n\t" /* set interrupt */
151 "str r10, [r12, #0x1c]\n\t"
152#else
153 "ldr r10, [r12] \n\t"
154 "orr r10, r10, #0x2 \n\t" /* set interrupt */
155 "str r10, [r12] \n\t"
156#endif
157 "b .exit \n\t"
158 );
159}
160#else /* !(CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002) */
161void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
162void fiq(void)
163{
164 /* Clear interrupt */
165#if CONFIG_CPU == PP5020
166 IISCONFIG &= ~0x2;
167#elif CONFIG_CPU == PP5002
168 inl(0xcf001040);
169 IISFIFO_CFG &= ~(1<<9);
170#endif
171
172 do {
173 while (p_size) {
174 if (FIFO_FREE_COUNT < 2) {
175 /* Enable interrupt */
176#if CONFIG_CPU == PP5020
177 IISCONFIG |= 0x2;
178#elif CONFIG_CPU == PP5002
179 IISFIFO_CFG |= (1<<9);
180#endif
181 return;
182 }
183
184 IISFIFO_WR = (*(p++))<<16;
185 IISFIFO_WR = (*(p++))<<16;
186 p_size-=4;
187 }
188
189 /* p is empty, get some more data */
190 if (pcm_callback_for_more) {
191 pcm_callback_for_more((unsigned char**)&p,&p_size);
192 }
193 } while (p_size);
194
195 /* No more data, so disable the FIFO/FIQ */
196 pcm_play_dma_stop();
197}
198#endif /* CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 */
199
200void pcm_play_dma_start(const void *addr, size_t size)
201{
202 p=(unsigned short*)addr;
203 p_size=size;
204
205 pcm_playing = true;
206
207#if CONFIG_CPU == PP5020
208 /* setup I2S interrupt for FIQ */
209 outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
210 outl(I2S_MASK, 0x60004024);
211#elif CONFIG_CPU == PP5024
212#else
213 /* setup I2S interrupt for FIQ */
214 outl(inl(0xcf00102c) | DMA_OUT_MASK, 0xcf00102c);
215 outl(DMA_OUT_MASK, 0xcf001024);
216#endif
217
218 /* Clear the FIQ disable bit in cpsr_c */
219 enable_fiq(fiq);
220
221 /* Enable playback FIFO */
222#if CONFIG_CPU == PP5020
223 IISCONFIG |= 0x20000000;
224#elif CONFIG_CPU == PP5002
225 IISCONFIG |= 0x4;
226#endif
227
228 /* Fill the FIFO - we assume there are enough bytes in the pcm buffer to
229 fill the 32-byte FIFO. */
230 while (p_size > 0) {
231 if (FIFO_FREE_COUNT < 2) {
232 /* Enable interrupt */
233#if CONFIG_CPU == PP5020
234 IISCONFIG |= 0x2;
235#elif CONFIG_CPU == PP5002
236 IISFIFO_CFG |= (1<<9);
237#endif
238 return;
239 }
240
241 IISFIFO_WR = (*(p++))<<16;
242 IISFIFO_WR = (*(p++))<<16;
243 p_size-=4;
244 }
245}
246
247/* Stops the DMA transfer and interrupt */
248void pcm_play_dma_stop(void)
249{
250 pcm_playing = false;
251
252#if CONFIG_CPU == PP5020
253
254 /* Disable playback FIFO */
255 IISCONFIG &= ~0x20000000;
256
257 /* Disable the interrupt */
258 IISCONFIG &= ~0x2;
259
260#elif CONFIG_CPU == PP5002
261
262 /* Disable playback FIFO */
263 IISCONFIG &= ~0x4;
264
265 /* Disable the interrupt */
266 IISFIFO_CFG &= ~(1<<9);
267#endif
268
269 disable_fiq();
270}
271
272void pcm_play_pause_pause(void)
273{
274#if CONFIG_CPU == PP5020
275 /* Disable the interrupt */
276 IISCONFIG &= ~0x2;
277 /* Disable playback FIFO */
278 IISCONFIG &= ~0x20000000;
279#elif CONFIG_CPU == PP5002
280 /* Disable the interrupt */
281 IISFIFO_CFG &= ~(1<<9);
282 /* Disable playback FIFO */
283 IISCONFIG &= ~0x4;
284#endif
285 disable_fiq();
286}
287
288void pcm_play_pause_unpause(void)
289{
290 /* Enable the FIFO and fill it */
291
292 enable_fiq(fiq);
293
294 /* Enable playback FIFO */
295#if CONFIG_CPU == PP5020
296 IISCONFIG |= 0x20000000;
297#elif CONFIG_CPU == PP5002
298 IISCONFIG |= 0x4;
299#endif
300
301 /* Fill the FIFO - we assume there are enough bytes in the
302 pcm buffer to fill the 32-byte FIFO. */
303 while (p_size > 0) {
304 if (FIFO_FREE_COUNT < 2) {
305 /* Enable interrupt */
306#if CONFIG_CPU == PP5020
307 IISCONFIG |= 0x2;
308#elif CONFIG_CPU == PP5002
309 IISFIFO_CFG |= (1<<9);
310#endif
311 return;
312 }
313
314 IISFIFO_WR = (*(p++))<<16;
315 IISFIFO_WR = (*(p++))<<16;
316 p_size-=4;
317 }
318}
319
320void pcm_set_frequency(unsigned int frequency)
321{
322 (void)frequency;
323 pcm_freq = HW_SAMPR_DEFAULT;
324}
325
326size_t pcm_get_bytes_waiting(void)
327{
328 return p_size;
329}
330
331#ifdef HAVE_PP5024_CODEC
332void pcm_init(void)
333{
334}
335#else
336void pcm_init(void)
337{
338 pcm_playing = false;
339 pcm_paused = false;
340 pcm_callback_for_more = NULL;
341
342 /* Initialize default register values. */
343 audiohw_init();
344
345 /* Power on */
346 audiohw_enable_output(true);
347
348 /* Unmute the master channel (DAC should be at zero point now). */
349 audiohw_mute(false);
350
351 /* Call pcm_play_dma_stop to initialize everything. */
352 pcm_play_dma_stop();
353}
354#endif /* HAVE_PP5024_CODEC */
355
356
357/****************************************************************************
358 ** Recording DMA transfer
359 **/
360static short peak_l, peak_r IBSS_ATTR;
361
362void fiq_record(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
363void fiq_record(void)
364{
365 short value;
366 pcm_more_callback_type2 more_ready;
367 int status = 0;
368
369 /* Clear interrupt */
370#if CONFIG_CPU == PP5020
371 IISCONFIG &= ~0x01;
372#elif CONFIG_CPU == PP5002
373 /* TODO */
374#endif
375
376 while (p_size > 0) {
377 if (FIFO_FREE_COUNT < 2) {
378 /* enable interrupt */
379#if CONFIG_CPU == PP5020
380 IISCONFIG |= 0x01;
381#elif CONFIG_CPU == PP5002
382 /* TODO */
383#endif
384 return;
385 }
386 value = (unsigned short)(IISFIFO_RD >> 16);
387 if (value > peak_l) peak_l = value;
388 else if (-value > peak_l) peak_l = -value;
389 *(p++) = value;
390
391 value = (unsigned short)(IISFIFO_RD >> 16);
392 if (value > peak_r) peak_r = value;
393 else if (-value > peak_r) peak_r = -value;
394 *(p++) = value;
395
396 p_size -= 4;
397
398 /* If we have filled the current chunk, start a new one */
399 if (p_size == 0) {
400 rec_peak_left = peak_l;
401 rec_peak_right = peak_r;
402 peak_l = peak_r = 0;
403 }
404 }
405
406 more_ready = pcm_callback_more_ready;
407
408 if (more_ready != NULL && more_ready(status) >= 0)
409 return;
410
411 /* Finished recording */
412 pcm_rec_dma_stop();
413}
414
415/* Continue transferring data in */
416void pcm_record_more(void *start, size_t size)
417{
418 rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
419 p = start;
420 p_size = size; /* Bytes to transfer */
421#if CONFIG_CPU == PP5020
422 IISCONFIG |= 0x01;
423#elif CONFIG_CPU == PP5002
424 /* TODO */
425#endif
426}
427
428void pcm_rec_dma_stop(void)
429{
430 logf("pcm_rec_dma_stop");
431
432 /* disable fifo */
433 IISCONFIG &= ~0x10000000;
434
435 disable_fiq();
436
437 pcm_recording = false;
438}
439
440void pcm_rec_dma_start(void *addr, size_t size)
441{
442 logf("pcm_rec_dma_start");
443
444 pcm_recording = true;
445
446 peak_l = peak_r = 0;
447 p_size = size;
448 p = addr;
449
450 /* setup FIQ */
451 outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
452 outl(I2S_MASK, 0x60004024);
453
454 /* interrupt on full fifo */
455 outl(inl(0x70002800) | 0x1, 0x70002800);
456
457 /* enable record fifo */
458 outl(inl(0x70002800) | 0x10000000, 0x70002800);
459
460 enable_fiq(fiq_record);
461}
462
463void pcm_close_recording(void)
464{
465 logf("pcm_close_recording");
466
467 pcm_rec_dma_stop();
468
469#if (CONFIG_CPU == PP5020)
470 disable_fiq();
471
472 /* disable fifo */
473 IISCONFIG &= ~0x10000000;
474
475 /* Clear interrupt */
476 IISCONFIG &= ~0x01;
477#endif
478} /* pcm_close_recording */
479
480void pcm_init_recording(void)
481{
482 logf("pcm_init_recording");
483
484 pcm_recording = false;
485 pcm_callback_more_ready = NULL;
486
487#if (CONFIG_CPU == PP5020)
488#if defined(IPOD_COLOR) || defined (IPOD_4G)
489 /* The usual magic from IPL - I'm guessing this configures the headphone
490 socket to be input or output - in this case, input. */
491 GPIOI_OUTPUT_VAL &= ~0x40;
492 GPIOA_OUTPUT_VAL &= ~0x4;
493#endif
494 /* Setup the recording FIQ handler */
495 *((unsigned int*)(15*4)) = (unsigned int)&fiq_record;
496#endif
497
498 pcm_rec_dma_stop();
499} /* pcm_init */
500
501void pcm_calculate_rec_peaks(int *left, int *right)
502{
503 *left = rec_peak_left;
504 *right = rec_peak_right;
505}
506
507/*
508 * This function goes directly into the DMA buffer to calculate the left and
509 * right peak values. To avoid missing peaks it tries to look forward two full
510 * peek periods (2/HZ sec, 100% overlap), although it's always possible that
511 * the entire period will not be visible. To reduce CPU load it only looks at
512 * every third sample, and this can be reduced even further if needed (even
513 * every tenth sample would still be pretty accurate).
514 */
515
516/* Check for a peak every PEAK_STRIDE samples */
517#define PEAK_STRIDE 3
518/* Up to 1/50th of a second of audio for peak calculation */
519/* This should use NATIVE_FREQUENCY, or eventually an adjustable freq. value */
520#define PEAK_SAMPLES (44100/50)
521void pcm_calculate_peaks(int *left, int *right)
522{
523 short *addr;
524 short *end;
525 {
526 size_t samples = p_size / 4;
527 addr = p;
528
529 if (samples > PEAK_SAMPLES)
530 samples = PEAK_SAMPLES - (PEAK_STRIDE - 1);
531 else
532 samples -= MIN(PEAK_STRIDE - 1, samples);
533
534 end = &addr[samples * 2];
535 }
536
537 if (left && right) {
538 int left_peak = 0, right_peak = 0;
539
540 while (addr < end) {
541 int value;
542 if ((value = addr [0]) > left_peak)
543 left_peak = value;
544 else if (-value > left_peak)
545 left_peak = -value;
546
547 if ((value = addr [PEAK_STRIDE | 1]) > right_peak)
548 right_peak = value;
549 else if (-value > right_peak)
550 right_peak = -value;
551
552 addr = &addr[PEAK_STRIDE * 2];
553 }
554
555 *left = left_peak;
556 *right = right_peak;
557 }
558 else if (left || right) {
559 int peak_value = 0, value;
560
561 if (right)
562 addr += (PEAK_STRIDE | 1);
563
564 while (addr < end) {
565 if ((value = addr [0]) > peak_value)
566 peak_value = value;
567 else if (-value > peak_value)
568 peak_value = -value;
569
570 addr += PEAK_STRIDE * 2;
571 }
572
573 if (left)
574 *left = peak_value;
575 else
576 *right = peak_value;
577 }
578}