summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/keymaps/keymap-e200.c20
-rw-r--r--apps/settings_list.c6
-rw-r--r--firmware/SOURCES5
-rw-r--r--firmware/drivers/audio/as3514.c309
-rw-r--r--firmware/export/audio.h3
-rw-r--r--firmware/export/audiohw.h3
-rw-r--r--firmware/export/config-e200.h15
-rw-r--r--firmware/export/pcm_sampr.h15
-rw-r--r--firmware/sound.c2
-rw-r--r--firmware/target/arm/pcm-pp.c202
-rw-r--r--firmware/target/arm/sandisk/sansa-e200/ata-e200.c11
-rw-r--r--firmware/target/arm/sandisk/sansa-e200/audio-e200.c103
12 files changed, 560 insertions, 134 deletions
diff --git a/apps/keymaps/keymap-e200.c b/apps/keymaps/keymap-e200.c
index 783d86f..55e30ca 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[] = {
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
}; /* button_context_pitchscreen */
+/** Recording Screen **/
+static const struct button_mapping button_context_recscreen[] = {
+ { ACTION_REC_PAUSE, BUTTON_UP|BUTTON_REL, BUTTON_UP },
+ { ACTION_STD_CANCEL, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
+ { ACTION_REC_NEWFILE, BUTTON_REC|BUTTON_REL, BUTTON_REC },
+ { ACTION_STD_MENU, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE },
+ { ACTION_SETTINGS_INC, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE },
+ { ACTION_SETTINGS_DEC, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_STD_PREV, BUTTON_SCROLL_UP, BUTTON_NONE },
+ { ACTION_STD_PREV, BUTTON_SCROLL_UP|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_STD_NEXT, BUTTON_SCROLL_DOWN, BUTTON_NONE },
+ { ACTION_STD_NEXT, BUTTON_SCROLL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
+
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_recscreen */
+
static const struct button_mapping button_context_keyboard[] = {
{ ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE },
{ ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
@@ -272,6 +290,8 @@ const struct button_mapping* get_context_mapping(int context)
return button_context_quickscreen;
case CONTEXT_PITCHSCREEN:
return button_context_pitchscreen;
+ case CONTEXT_RECSCREEN:
+ return button_context_recscreen;
case CONTEXT_KEYBOARD:
return button_context_keyboard;
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 23bb81a..f91cacf 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -792,15 +792,21 @@ const struct settings_list settings[] = {
{F_T_INT|F_RECSETTING,&global_settings.cliplight,LANG_CLIP_LIGHT,INT(0),
"cliplight","off,main,both,remote",UNUSED},
#endif
+#ifdef DEFAULT_REC_MIC_GAIN
{F_T_INT|F_RECSETTING,&global_settings.rec_mic_gain,
LANG_RECORDING_GAIN,INT(DEFAULT_REC_MIC_GAIN),
"rec mic gain",NULL,UNUSED},
+#endif /* DEFAULT_REC_MIC_GAIN */
+#ifdef DEFAULT_REC_LEFT_GAIN
{F_T_INT|F_RECSETTING,&global_settings.rec_left_gain,
LANG_RECORDING_LEFT,INT(DEFAULT_REC_LEFT_GAIN),
"rec left gain",NULL,UNUSED},
+#endif /* DEFAULT_REC_LEFT_GAIN */
+#ifdef DEFAULT_REC_RIGHT_GAIN
{F_T_INT|F_RECSETTING,&global_settings.rec_right_gain,LANG_RECORDING_RIGHT,
INT(DEFAULT_REC_RIGHT_GAIN),
"rec right gain",NULL,UNUSED},
+#endif /* DEFAULT_REC_RIGHT_GAIN */
#if CONFIG_CODEC == MAS3587F
{F_T_INT|F_RECSETTING,&global_settings.rec_frequency,
LANG_RECORDING_FREQUENCY,
diff --git a/firmware/SOURCES b/firmware/SOURCES
index fdb457c..70bd12e 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -296,7 +296,9 @@ target/arm/system-pp502x.c
target/arm/crt0-pp-bl.S
#else
target/arm/pcm-pp.c
+#ifndef SANSA_E200
target/arm/audio-pp.c
+#endif /* SANSA_E200 */
target/arm/crt0-pp.S
#endif
#elif CONFIG_CPU == PNX0101
@@ -375,6 +377,9 @@ target/arm/usb-pp.c
target/arm/sandisk/sansa-e200/button-e200.c
target/arm/sandisk/sansa-e200/power-e200.c
target/arm/i2s-pp.c
+#ifndef BOOTLOADER
+target/arm/sandisk/sansa-e200/audio-e200.c
+#endif /* BOOTLOADER */
#endif /* SIMULATOR */
#endif /* SANSA_E200 */
diff --git a/firmware/drivers/audio/as3514.c b/firmware/drivers/audio/as3514.c
index 3c11caa..982bbe1 100644
--- a/firmware/drivers/audio/as3514.c
+++ b/firmware/drivers/audio/as3514.c
@@ -22,46 +22,76 @@
#include "cpu.h"
#include "debug.h"
#include "system.h"
+#include "audio.h"
#include "audiohw.h"
#include "i2s.h"
#include "i2c-pp.h"
const struct sound_settings_info audiohw_settings[] = {
- [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25},
+ [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25},
/* HAVE_SW_TONE_CONTROLS */
- [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
- [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
- [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
- [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
- [SOUND_STEREO_WIDTH] = {"%", 0, 1, 0, 255, 100},
+ [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
+ [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
+ [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
+ [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
+ [SOUND_STEREO_WIDTH] = {"%", 0, 1, 0, 255, 100},
+ [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 39, 23},
+ [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23},
+ [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23},
};
/* Shadow registers */
-int as3514_regs[0x1E]; /* last audio register: PLLMODE 0x1d */
+struct as3514_info
+{
+ int vol_r; /* Cached volume level (R) */
+ int vol_l; /* Cached volume level (L) */
+ unsigned int regs[0x1e]; /* last audio register: PLLMODE 0x1d */
+} as3514;
+
+enum
+{
+ SOURCE_DAC = 0,
+ SOURCE_MIC1,
+ SOURCE_LINE_IN1,
+ SOURCE_LINE_IN1_ANALOG
+};
+
+static unsigned int source = SOURCE_DAC;
/*
* little helper method to set register values.
- * With the help of as3514_regs, we minimize i2c
+ * With the help of as3514.regs, we minimize i2c
* traffic.
*/
-static void as3514_write(int reg, int value)
+static void as3514_write(unsigned int reg, unsigned int value)
{
if (pp_i2c_send(AS3514_I2C_ADDR, reg, value) != 2)
{
- DEBUGF("as3514 error reg=0x%x", reg);
+ DEBUGF("as3514 error reg=0x%02x", reg);
}
- if ((unsigned int)reg < sizeof(as3514_regs) / sizeof(int))
+ if (reg < ARRAYLEN(as3514.regs))
{
- as3514_regs[reg] = value;
+ as3514.regs[reg] = value;
}
else
{
- DEBUGF("as3514 error reg=0x%x", reg);
+ DEBUGF("as3514 error reg=0x%02x", reg);
}
}
+/* Helpers to set/clear bits */
+static void as3514_write_or(unsigned int reg, unsigned int bits)
+{
+ as3514_write(reg, as3514.regs[reg] | bits);
+}
+
+static void as3514_write_and(unsigned int reg, unsigned int bits)
+{
+ as3514_write(reg, as3514.regs[reg] & bits);
+}
+
/* convert tenth of dB volume to master volume register value */
int tenthdb2master(int db)
{
@@ -75,6 +105,26 @@ int tenthdb2master(int db)
}
}
+int sound_val2phys(int setting, int value)
+{
+ int result;
+
+ switch(setting)
+ {
+ case SOUND_LEFT_GAIN:
+ case SOUND_RIGHT_GAIN:
+ case SOUND_MIC_GAIN:
+ result = (value - 23) * 15;
+ break;
+
+ default:
+ result = value;
+ break;
+ }
+
+ return result;
+}
+
void audiohw_reset(void);
/*
@@ -110,20 +160,33 @@ int audiohw_init(void)
i2s_reset();
/* Set ADC off, mixer on, DAC on, line out off, line in off, mic off */
- as3514_write(AUDIOSET1, 0x64); /* Turn on SUM, DAC, LineIn 1 */
- as3514_write(AUDIOSET3, 0x5); /* Set HPCM off, ZCU off*/
- as3514_write(HPH_OUT_R, 0xc0 | 0x16); /* set vol and set speaker over-current to 0 */
- as3514_write(HPH_OUT_L, 0x16); /* set default vol for headphone */
-#if 0
- as3514_write(LINE_IN1_R, 0x36); /* unmute lineIn 1 and set gain */
- as3514_write(LINE_IN1_L, 0x36); /* unmute lineIn 1 and set gain */
-#endif
+
+ /* Turn on SUM, DAC */
+ as3514_write(AUDIOSET1, (1 << 6) | (1 << 5));
+
+ /* Set HPCM off, ZCU off*/
+ as3514_write(AUDIOSET3, (1 << 2) | (1 << 0));
+
+ /* set vol and set speaker over-current to 0 */
+ as3514_write(HPH_OUT_R, (0x3 << 6) | 0x16);
+ /* set default vol for headphone */
+ as3514_write(HPH_OUT_L, 0x16);
+
+ /* LRCK 24-48kHz */
as3514_write(PLLMODE, 0x00);
+ /* DAC_Mute_off */
+ as3514_write_or(DAC_L, (1 << 6));
+
+ /* M1_Sup_off */
+ as3514_write_or(MIC1_L, (1 << 7));
+ /* M2_Sup_off */
+ as3514_write_or(MIC2_L, (1 << 7));
+
/* read all reg values */
- for (i = 0; i < sizeof(as3514_regs) / sizeof(int); i++)
+ for (i = 0; i < ARRAYLEN(as3514.regs); i++)
{
- as3514_regs[i] = i2c_readbyte(AS3514_I2C_ADDR, i);
+ as3514.regs[i] = i2c_readbyte(AS3514_I2C_ADDR, i);
}
return 0;
@@ -136,75 +199,80 @@ void audiohw_postinit(void)
/* Silently enable / disable audio output */
void audiohw_enable_output(bool enable)
{
- int curr;
- curr = as3514_regs[HPH_OUT_L];
-
- if (enable)
- {
+ if (enable) {
/* reset the I2S controller into known state */
i2s_reset();
- as3514_write(HPH_OUT_L, curr | 0x40); /* power on */
+ as3514_write_or(HPH_OUT_L, (1 << 6)); /* power on */
audiohw_mute(0);
} else {
audiohw_mute(1);
- as3514_write(HPH_OUT_L, curr & ~(0x40)); /* power off */
+ as3514_write_and(HPH_OUT_L, ~(1 << 6)); /* power off */
}
}
int audiohw_set_master_vol(int vol_l, int vol_r)
{
- int hph_r = as3514_regs[HPH_OUT_R] & ~0x1f;
- int hph_l = as3514_regs[HPH_OUT_L] & ~0x1f;
-
- /* we are controling dac volume instead of headphone volume,
- as the volume is bigger.
- HDP: 1.07 dB gain
- DAC: 6 dB gain
- */
- if(vol_r <= 0x16)
- {
- as3514_write(DAC_R, vol_r);
- as3514_write(HPH_OUT_R, hph_r); /* set 0 */
- }
- else
- {
- as3514_write(DAC_R, 0x16);
- as3514_write(HPH_OUT_R, hph_r + (vol_r - 0x16));
+ unsigned int hph_r = as3514.regs[HPH_OUT_R] & ~0x1f;
+ unsigned int hph_l = as3514.regs[HPH_OUT_L] & ~0x1f;
+ unsigned int mix_l, mix_r;
+ unsigned int mix_reg_r, mix_reg_l;
+
+ /* keep track of current setting */
+ as3514.vol_l = vol_l;
+ as3514.vol_r = vol_r;
+
+ if (source == SOURCE_LINE_IN1_ANALOG) {
+ mix_reg_r = LINE_IN1_R;
+ mix_reg_l = LINE_IN1_L;
+ } else {
+ mix_reg_r = DAC_R;
+ mix_reg_l = DAC_L;
}
- if(vol_l <= 0x16)
- {
- as3514_write(DAC_L, 0x40 + vol_l);
- as3514_write(HPH_OUT_L, hph_l); /* set 0 */
+ mix_r = as3514.regs[mix_reg_r] & ~0x1f;
+ mix_l = as3514.regs[mix_reg_l] & ~0x1f;
+
+ /* we combine the mixer channel volume range with the headphone volume
+ range */
+ if (vol_r <= 0x16) {
+ mix_r |= vol_r;
+ /* hph_r - set 0 */
+ } else {
+ mix_r |= 0x16;
+ hph_r += vol_r - 0x16;
}
- else
- {
- as3514_write(DAC_L, 0x40 + 0x16);
- as3514_write(HPH_OUT_L, hph_l + (vol_l - 0x16));
+
+ if (vol_l <= 0x16) {
+ mix_l |= vol_l;
+ /* hph_l - set 0 */
+ } else {
+ mix_l |= 0x16;
+ hph_l += vol_l - 0x16;
}
+ as3514_write(mix_reg_r, mix_r);
+ as3514_write(mix_reg_l, mix_l);
+ as3514_write(HPH_OUT_R, hph_r);
+ as3514_write(HPH_OUT_L, hph_l);
+
return 0;
}
int audiohw_set_lineout_vol(int vol_l, int vol_r)
{
as3514_write(LINE_OUT_R, vol_r);
- as3514_write(LINE_OUT_L, 0x40 | vol_l);
+ as3514_write(LINE_OUT_L, (1 << 6) | vol_l);
return 0;
}
int audiohw_mute(int mute)
{
- int curr;
- curr = as3514_regs[HPH_OUT_L];
-
- if (mute)
- {
- as3514_write(HPH_OUT_L, curr | 0x80);
+ if (mute) {
+ as3514_write_or(HPH_OUT_L, (1 << 7));
} else {
- as3514_write(HPH_OUT_L, curr & ~(0x80));
+ as3514_write_and(HPH_OUT_L, ~(1 << 7));
}
return 0;
@@ -214,7 +282,7 @@ int audiohw_mute(int mute)
void audiohw_close(void)
{
/* mute headphones */
- audiohw_mute(1);
+ audiohw_mute(true);
/* turn off everything */
as3514_write(AUDIOSET1, 0x0);
@@ -227,21 +295,124 @@ void audiohw_set_sample_rate(int sampling_control)
void audiohw_enable_recording(bool source_mic)
{
- (void)source_mic;
+ if (source_mic) {
+ source = SOURCE_MIC1;
+
+ /* Sync mixer volumes before switching inputs */
+ audiohw_set_master_vol(as3514.vol_l, as3514.vol_r);
+
+ /* ADCmux = Stereo Microphone */
+ as3514_write_and(ADC_R, ~(0x3 << 6));
+ /* MIC1_on, LIN1_off */
+ as3514_write(AUDIOSET1,
+ (as3514.regs[AUDIOSET1] & ~(1 << 2)) | (1 << 0));
+ /* M1_AGC_off */
+ as3514_write_and(MIC1_R, ~(1 << 7));
+ } else {
+ source = SOURCE_LINE_IN1;
+
+ audiohw_set_master_vol(as3514.vol_l, as3514.vol_r);
+
+ /* ADCmux = Line_IN1 */
+ as3514_write(ADC_R,
+ (as3514.regs[ADC_R] & ~(0x3 << 6)) | (0x1 << 6));
+ /* MIC1_off, LIN1_on */
+ as3514_write(AUDIOSET1,
+ (as3514.regs[AUDIOSET1] & ~(1 << 0)) | (1 << 2));
+ }
+
+ /* ADC_Mute_off */
+ as3514_write_or(ADC_L, (1 << 6));
+ /* ADC_on */
+ as3514_write_or(AUDIOSET1, (1 << 7));
}
void audiohw_disable_recording(void)
{
+ source = SOURCE_DAC;
+
+ /* ADC_Mute_on */
+ as3514_write_and(ADC_L, ~(1 << 6));
+
+ /* ADC_off, LIN1_off, MIC_off */
+ as3514_write_and(AUDIOSET1, ~((1 << 7) | (1 << 2) | (1 << 0)));
+
+ audiohw_set_master_vol(as3514.vol_l, as3514.vol_r);
}
+/**
+ * Set recording volume
+ *
+ * Line in : 0 .. 23 .. 31 =>
+ Volume -34.5 .. +00.0 .. +12.0 dB
+ * Mic (left): 0 .. 23 .. 39 =>
+ * Volume -34.5 .. +00.0 .. +24.0 dB
+ *
+ */
void audiohw_set_recvol(int left, int right, int type)
{
- (void)left;
- (void)right;
- (void)type;
+ switch (type)
+ {
+ case AUDIO_GAIN_MIC:
+ {
+ /* Combine MIC gains seamlessly with ADC levels */
+ unsigned int mic1_r = as3514.regs[MIC1_R] & ~(0x3 << 5);
+
+ if (left >= 36) {
+ /* M1_Gain = +40db, ADR_Vol = +7.5dB .. +12.0 dB =>
+ +19.5 dB .. +24.0 dB */
+ left -= 8;
+ mic1_r |= (0x2 << 5);
+ } else if (left >= 32) {
+ /* M1_Gain = +34db, ADR_Vol = +7.5dB .. +12.0 dB =>
+ +13.5 dB .. +18.0 dB */
+ left -= 4;
+ mic1_r |= (0x1 << 5);
+ }
+ /* M1_Gain = +28db, ADR_Vol = -34.5dB .. +12.0 dB =>
+ -34.5 dB .. +12.0 dB */
+
+ right = left;
+
+ as3514_write(MIC1_R, mic1_r);
+ break;
+ }
+ case AUDIO_GAIN_LINEIN:
+ break;
+ default:
+ return;
+ }
+
+ as3514_write(ADC_R, (as3514.regs[ADC_R] & ~0x1f) | right);
+ as3514_write(ADC_L, (as3514.regs[ADC_L] & ~0x1f) | left);
}
+/**
+ * Enable line in 1 analog monitoring
+ *
+ */
void audiohw_set_monitor(int enable)
{
- (void)enable;
+ /* LI1R_Mute_on - default */
+ unsigned int line_in1_r = as3514.regs[LINE_IN1_R] & ~(1 << 5);
+ /* LI1L_Mute_on - default */
+ unsigned int line_in1_l = as3514.regs[LINE_IN1_L] & ~(1 << 5);
+ /* LIN1_off - default */
+ unsigned int audioset1 = as3514.regs[AUDIOSET1] & ~(1 << 2);
+
+ if (enable) {
+ source = SOURCE_LINE_IN1_ANALOG;
+ audiohw_set_master_vol(as3514.vol_l, as3514.vol_r);
+
+ /* LI1R_Mute_off */
+ line_in1_r |= (1 << 5);
+ /* LI1L_Mute_off */
+ line_in1_l |= (1 << 5);
+ /* LIN1_on */
+ audioset1 |= (1 << 2);
+ }
+
+ as3514_write(AUDIOSET1, audioset1);
+ as3514_write(LINE_IN1_R, line_in1_r);
+ as3514_write(LINE_IN1_L, line_in1_l);
}
diff --git a/firmware/export/audio.h b/firmware/export/audio.h
index a0da846..a79a734 100644
--- a/firmware/export/audio.h
+++ b/firmware/export/audio.h
@@ -139,6 +139,9 @@ enum audio_sources
AUDIO_SRC_DEFAULT = AUDIO_SRC_PLAYBACK
};
+extern int audio_channels;
+extern int audio_output_source;
+
#ifdef HAVE_RECORDING
/* Recordable source implies it has the input as well */
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h
index 3838b00..65a2466 100644
--- a/firmware/export/audiohw.h
+++ b/firmware/export/audiohw.h
@@ -58,7 +58,8 @@ enum {
SOUND_SUPERBASS,
#endif
#if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320)\
- || defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8731)
+ || defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8731) \
+ || defined(HAVE_AS3514)
SOUND_LEFT_GAIN,
SOUND_RIGHT_GAIN,
SOUND_MIC_GAIN,
diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h
index 9d4fb1c..001c89b 100644
--- a/firmware/export/config-e200.h
+++ b/firmware/export/config-e200.h
@@ -7,11 +7,22 @@
#define MODEL_NUMBER 16
#define MODEL_NAME "Sandisk Sansa e200"
+#define HW_SAMPR_CAPS (SAMPR_CAP_44)
+
/* define this if you have recording possibility */
-/*#define HAVE_RECORDING*/ /* TODO: add support for this */
+#define HAVE_RECORDING
+
+#define DEFAULT_REC_MIC_GAIN 23
+#define DEFAULT_REC_LEFT_GAIN 23
+#define DEFAULT_REC_RIGHT_GAIN 23
+
+#define REC_SAMPR_CAPS (SAMPR_CAP_22)
+#define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */
+#define REC_SAMPR_DEFAULT SAMPR_22
+
/* Define bitmask of input sources - recordable bitmask can be defined
explicitly if different */
-/* #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) */
+#define INPUT_SRC_CAPS (SRC_CAP_MIC)
/* define this if you have a bitmap LCD display */
#define HAVE_LCD_BITMAP
diff --git a/firmware/export/pcm_sampr.h b/firmware/export/pcm_sampr.h
index 27a300d..b27050e 100644
--- a/firmware/export/pcm_sampr.h
+++ b/firmware/export/pcm_sampr.h
@@ -292,18 +292,13 @@ enum rec_freq_indexes
#define REC_HAVE_8_(...)
#endif
REC_NUM_FREQ,
- /* This should always come out I reckon */
- REC_FREQ_DEFAULT = REC_FREQ_44,
- /* Get the minimum bitcount needed to save the range of values */
- REC_FREQ_CFG_NUM_BITS = (REC_NUM_FREQ > 8 ?
- 4 : (REC_NUM_FREQ > 4 ?
- 3 : (REC_NUM_FREQ > 2 ?
- 2 : 1
- )
- )
- ),
}; /* enum rec_freq_indexes */
+/* Default to 44.1kHz if not otherwise specified */
+#ifndef REC_FREQ_DEFAULT
+#define REC_FREQ_DEFAULT REC_FREQ_44
+#endif
+
#define REC_FREQ_CFG_VAL_LIST &REC_HAVE_96_(",96") REC_HAVE_88_(",88") \
REC_HAVE_64_(",64") REC_HAVE_48_(",48") \
REC_HAVE_44_(",44") REC_HAVE_32_(",32") \
diff --git a/firmware/sound.c b/firmware/sound.c
index 9e4481c..0ccf1df 100644
--- a/firmware/sound.c
+++ b/firmware/sound.c
@@ -743,6 +743,7 @@ void sound_set(int setting, int value)
sound_set_val(value);
}
+#ifndef HAVE_AS3514
int sound_val2phys(int setting, int value)
{
#if CONFIG_CODEC == MAS3587F
@@ -804,6 +805,7 @@ int sound_val2phys(int setting, int value)
return value;
#endif
}
+#endif /* HAVE_AS3514 */
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
#ifndef SIMULATOR
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c
index 41bd92b..9027ff1 100644
--- a/firmware/target/arm/pcm-pp.c
+++ b/firmware/target/arm/pcm-pp.c
@@ -160,7 +160,7 @@ void fiq(void)
{
/* Clear interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
- IISCONFIG &= ~0x2;
+ IISCONFIG &= ~(1 << 1);
#elif CONFIG_CPU == PP5002
inl(0xcf001040);
IISFIFO_CFG &= ~(1<<9);
@@ -171,7 +171,7 @@ void fiq(void)
if (FIFO_FREE_COUNT < 2) {
/* Enable interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
- IISCONFIG |= 0x2;
+ IISCONFIG |= (1 << 1);
#elif CONFIG_CPU == PP5002
IISFIFO_CFG |= (1<<9);
#endif
@@ -221,7 +221,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
/* Enable playback FIFO */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
- IISCONFIG |= 0x20000000;
+ IISCONFIG |= (1 << 29);
#elif CONFIG_CPU == PP5002
IISCONFIG |= 0x4;
#endif
@@ -232,7 +232,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
if (FIFO_FREE_COUNT < 2) {
/* Enable interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
- IISCONFIG |= 0x2;
+ IISCONFIG |= (1 << 1);
#elif CONFIG_CPU == PP5002
IISFIFO_CFG |= (1<<9);
#endif
@@ -257,13 +257,8 @@ void pcm_play_dma_stop(void)
pcm_paused = false;
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
-
- /* Disable playback FIFO */
- IISCONFIG &= ~0x20000000;
-
- /* Disable the interrupt */
- IISCONFIG &= ~0x2;
-
+ /* Disable playback FIFO and interrupt */
+ IISCONFIG &= ~((1 << 29) | (1 << 1));
#elif CONFIG_CPU == PP5002
/* Disable playback FIFO */
@@ -279,10 +274,8 @@ void pcm_play_dma_stop(void)
void pcm_play_pause_pause(void)
{
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
- /* Disable the interrupt */
- IISCONFIG &= ~0x2;
- /* Disable playback FIFO */
- IISCONFIG &= ~0x20000000;
+ /* Disable playback FIFO and interrupt */
+ IISCONFIG &= ~((1 << 29) | (1 << 1));
#elif CONFIG_CPU == PP5002
/* Disable the interrupt */
IISFIFO_CFG &= ~(1<<9);
@@ -301,7 +294,7 @@ void pcm_play_pause_unpause(void)
/* Enable playback FIFO */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
- IISCONFIG |= 0x20000000;
+ IISCONFIG |= (1 << 29);
#elif CONFIG_CPU == PP5002
IISCONFIG |= 0x4;
#endif
@@ -312,7 +305,7 @@ void pcm_play_pause_unpause(void)
if (FIFO_FREE_COUNT < 2) {
/* Enable interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
- IISCONFIG |= 0x2;
+ IISCONFIG |= (1 << 1);
#elif CONFIG_CPU == PP5002
IISFIFO_CFG |= (1<<9);
#endif
@@ -369,6 +362,79 @@ void pcm_postinit(void)
** Recording DMA transfer
**/
#ifdef HAVE_RECORDING
+
+#ifdef HAVE_AS3514
+void fiq_record(void) ICODE_ATTR __attribute__((naked));
+void fiq_record(void)
+{
+ register pcm_more_callback_type2 more_ready;
+ register int32_t value1, value2;
+
+ asm volatile ("stmfd sp!, {r0-r7, ip, lr} \n"); /* Store context */
+
+ IISCONFIG &= ~(1 << 0);
+
+ if (audio_channels == 2) {
+ /* RX is stereo */
+ while (p_size > 0) {
+ if (FIFO_FREE_COUNT < 2) {
+ /* enable interrupt */
+ IISCONFIG |= (1 << 0);
+ goto fiq_record_exit;
+ }
+
+ /* Discard every other sample since ADC clock is 1/2 LRCK */
+ value1 = IISFIFO_RD;
+ value2 = IISFIFO_RD;
+
+ *(int32_t *)p = value1;
+ p += 2;
+ p_size -= 4;
+
+ /* TODO: Figure out how to do IIS loopback */
+ if (audio_output_source != AUDIO_SRC_PLAYBACK) {
+ IISFIFO_WR = value1;
+ IISFIFO_WR = value1;
+ }
+ }
+ }
+ else {
+ /* RX is left channel mono */
+ while (p_size > 0) {
+ if (FIFO_FREE_COUNT < 2) {
+ /* enable interrupt */
+ IISCONFIG |= (1 << 0);
+ goto fiq_record_exit;
+ }
+
+ /* Discard every other sample since ADC clock is 1/2 LRCK */
+ value1 = IISFIFO_RD;
+ value2 = IISFIFO_RD;
+ *p++ = value1;
+ *p++ = value1;
+ p_size -= 4;
+
+ if (audio_output_source != AUDIO_SRC_PLAYBACK) {
+ value1 = *((int32_t *)p - 1);
+ IISFIFO_WR = value1;
+ IISFIFO_WR = value1;
+ }
+ }
+ }
+
+ more_ready = pcm_callback_more_ready;
+
+ if (more_ready == NULL || more_ready(0) < 0) {
+ /* Finished recording */
+ pcm_rec_dma_stop();
+ }
+
+fiq_record_exit:
+ asm volatile("ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
+ "subs pc, lr, #4 \n"); /* Return from FIQ */
+}
+
+#else
static short peak_l, peak_r IBSS_ATTR;
void fiq_record(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
@@ -380,7 +446,7 @@ void fiq_record(void)
/* Clear interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
- IISCONFIG &= ~0x01;
+ IISCONFIG &= ~(1 << 0);
#elif CONFIG_CPU == PP5002
/* TODO */
#endif
@@ -389,12 +455,13 @@ void fiq_record(void)
if (FIFO_FREE_COUNT < 2) {
/* enable interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
- IISCONFIG |= 0x01;
+ IISCONFIG |= (1 << 0);
#elif CONFIG_CPU == PP5002
/* TODO */
#endif
return;
}
+
value = (unsigned short)(IISFIFO_RD >> 16);
if (value > peak_l) peak_l = value;
else if (-value > peak_l) peak_l = -value;
@@ -424,16 +491,18 @@ void fiq_record(void)
pcm_rec_dma_stop();
}
+#endif /* HAVE_AS3514 */
+
/* Continue transferring data in */
void pcm_record_more(void *start, size_t size)
{
- rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
- p = start;
- p_size = size; /* Bytes to transfer */
+ rec_peak_addr = start; /* Start peaking at dest */
+ p = start; /* Start of RX buffer */
+ p_size = size; /* Bytes to transfer */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
- IISCONFIG |= 0x01;
+ IISCONFIG |= (1 << 0);
#elif CONFIG_CPU == PP5002
- /* TODO */
+ /* TODO */
#endif
}
@@ -441,11 +510,14 @@ void pcm_rec_dma_stop(void)
{
logf("pcm_rec_dma_stop");
- /* disable fifo */
- IISCONFIG &= ~0x10000000;
-
disable_fiq();
+ /* clear interrupt, disable fifo */
+ IISCONFIG &= ~((1 << 28) | (1 << 0));
+
+ /* clear rx fifo */
+ IISFIFO_CFG |= (1 << 12);
+
pcm_recording = false;
}
@@ -455,7 +527,10 @@ void pcm_rec_dma_start(void *addr, size_t size)
pcm_recording = true;
+#ifndef HAVE_AS3514
peak_l = peak_r = 0;
+#endif
+
p_size = size;
p = addr;
@@ -463,11 +538,8 @@ void pcm_rec_dma_start(void *addr, size_t size)
CPU_INT_PRIORITY |= I2S_MASK;
CPU_INT_EN = I2S_MASK;
- /* interrupt on full fifo */
- IISCONFIG |= 0x1;
-
- /* enable record fifo */
- IISCONFIG |= 0x10000000;
+ /* interrupt on full fifo, enable record fifo */
+ IISCONFIG |= (1 << 28) | (1 << 0);
set_fiq_handler(fiq_record);
enable_fiq();
@@ -476,18 +548,7 @@ void pcm_rec_dma_start(void *addr, size_t size)
void pcm_close_recording(void)
{
logf("pcm_close_recording");
-
pcm_rec_dma_stop();
-
-#if (CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024)
- disable_fiq();
-
- /* disable fifo */
- IISCONFIG &= ~0x10000000;
-
- /* Clear interrupt */
- IISCONFIG &= ~0x01;
-#endif
} /* pcm_close_recording */
void pcm_init_recording(void)
@@ -505,7 +566,7 @@ void pcm_init_recording(void)
GPIOA_OUTPUT_VAL &= ~0x4;
#endif
/* Setup the recording FIQ handler */
- *((unsigned int*)(15*4)) = (unsigned int)&fiq_record;
+ set_fiq_handler(fiq_record);
#endif
pcm_rec_dma_stop();
@@ -513,10 +574,57 @@ void pcm_init_recording(void)
void pcm_calculate_rec_peaks(int *left, int *right)
{
- *left = rec_peak_left;
- *right = rec_peak_right;
+#ifdef HAVE_AS3514
+ if (pcm_recording)
+ {
+ unsigned long *start = rec_peak_addr;
+ unsigned long *end = (unsigned long *)p;
+
+ if (start < end)
+ {
+ unsigned long *addr = start;
+ long peak_l = 0, peak_r = 0;
+ long peaksq_l = 0, peaksq_r = 0;
+
+ do
+ {
+ long value = *addr;
+ long ch, chsq;
+
+ ch = (int16_t)value;
+ chsq = ch*ch;
+ if (chsq > peaksq_l)
+ peak_l = ch, peaksq_l = chsq;
+
+ ch = value >> 16;
+ chsq = ch*ch;
+ if (chsq > peaksq_r)
+ peak_r = ch, peaksq_r = chsq;
+
+ addr += 4;
+ }
+ while (addr < end);
+
+ if (start == rec_peak_addr)
+ rec_peak_addr = end;
+
+ rec_peak_left = abs(peak_l);
+ rec_peak_right = abs(peak_r);
+ }
+ }
+ else
+ {
+ rec_peak_left = rec_peak_right = 0;
+ }
+#endif /* HAVE_AS3514 */
+
+ if (left)
+ *left = rec_peak_left;
+
+ if (right)
+ *right = rec_peak_right;
}
-#endif
+#endif /* HAVE_RECORDING */
/*
* 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 29fe0d9..10c13cd 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)
while(((response >> 9) & 0xf) != state)
{
sd_send_command(SEND_STATUS, (card->rca) << 16, 1);
+ priority_yield();
sd_read_response(&response, 1);
/* TODO: Add a timeout and error handling */
}
@@ -442,7 +443,7 @@ void sd_init_device(void)
dataptr += (FIFO_SIZE*2); /* Advance one chunk of 16 words */
}
}
- mutex_init(&sd_mtx);
+ spinlock_init(&sd_mtx);
}
/* API Functions */
@@ -472,7 +473,7 @@ int ata_read_sectors(IF_MV2(int drive,)
#ifdef HAVE_MULTIVOLUME
(void)drive; /* unused for now */
#endif
- mutex_lock(&sd_mtx);
+ spinlock_lock(&sd_mtx);
last_disk_activity = current_tick;
spinup_start = current_tick;
@@ -530,7 +531,7 @@ int ata_read_sectors(IF_MV2(int drive,)
ata_led(false);
ata_enable(false);
- mutex_unlock(&sd_mtx);
+ spinlock_unlock(&sd_mtx);
return ret;
}
@@ -551,7 +552,7 @@ int ata_write_sectors(IF_MV2(int drive,)
long timeout;
tSDCardInfo *card = &card_info[current_card];
- mutex_lock(&sd_mtx);
+ spinlock_lock(&sd_mtx);
ata_enable(true);
ata_led(true);
if(current_card == 0)
@@ -607,7 +608,7 @@ retry:
sd_wait_for_state(card, TRAN);
ata_led(false);
ata_enable(false);
- mutex_unlock(&sd_mtx);
+ spinlock_unlock(&sd_mtx);
return ret;
}
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 0000000..a3f3284
--- /dev/null
+++ b/firmware/target/arm/sandisk/sansa-e200/audio-e200.c
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2007 by Michael Sevakis
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "system.h"
+#include "cpu.h"
+#include "audio.h"
+#include "sound.h"
+
+int audio_channels = 2;
+int audio_output_source = AUDIO_SRC_PLAYBACK;
+
+void audio_set_output_source(int source)
+{
+ int oldmode = set_fiq_status(FIQ_DISABLED);
+
+ if ((unsigned)source >= AUDIO_NUM_SOURCES)
+ source = AUDIO_SRC_PLAYBACK;
+
+ audio_output_source = source;
+
+ if (source != AUDIO_SRC_PLAYBACK)
+ IISCONFIG |= (1 << 29);
+
+ set_fiq_status(oldmode);
+} /* audio_set_output_source */
+
+void audio_set_source(int source, unsigned flags)
+{
+ static int last_source = AUDIO_SRC_PLAYBACK;
+#if 0
+ static bool last_recording = false;
+ bool recording = flags & SRCF_RECORDING;
+#endif
+ (void)flags;
+
+ switch (source)
+ {
+ default: /* playback - no recording */
+ source = AUDIO_SRC_PLAYBACK;
+ case AUDIO_SRC_PLAYBACK:
+ audio_channels = 2;
+ if (source != last_source)
+ {
+ audiohw_set_monitor(false);
+ audiohw_disable_recording();
+ }
+ break;
+
+ case AUDIO_SRC_MIC: /* recording only */
+ audio_channels = 1;
+ if (source != last_source)
+ {
+ audiohw_set_monitor(false);
+ audiohw_enable_recording(true); /* source mic */
+ }
+ break;
+
+#if 0
+ case AUDIO_SRC_FMRADIO: /* recording and playback */
+ audio_channels = 2;
+
+ if (!recording)
+ audiohw_set_recvol(23, 23, AUDIO_GAIN_LINEIN);
+
+ if (source == last_source && recording == last_recording)
+ break;
+
+ last_recording = recording;
+
+ if (recording)
+ {
+ audiohw_set_monitor(false);
+ audiohw_enable_recording(false);
+ }
+ else
+ {
+ audiohw_disable_recording();
+ audiohw_set_monitor(true); /* line 1 analog audio path */
+ }
+
+ break;
+#endif
+ } /* end switch */
+
+ last_source = source;
+} /* audio_set_source */
+
+