summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-06-05 07:03:30 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-06-05 07:03:30 +0000
commitbcb8a884ee256e31d45a46bdeb83423457ac48d2 (patch)
tree5452ef9fa0b3f968a30835d44360f35951f2a0d5 /firmware
parentfea88888f0bc271b57a6d6dfab387fddc1cbd20d (diff)
downloadrockbox-bcb8a884ee256e31d45a46bdeb83423457ac48d2.tar.gz
rockbox-bcb8a884ee256e31d45a46bdeb83423457ac48d2.zip
e200: Add recording. Just from MIC right now and FM integration will happen soon. Most every bit of weirdness is nescessary and no problems seem to exist that the retailos doesn't exhibit too (namely noise when LCD is on when recording from MIC).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13557 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-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
10 files changed, 534 insertions, 134 deletions
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
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 3c11caa4c7..982bbe16d3 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 a0da846215..a79a734e29 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 3838b007d0..65a2466dfc 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 9d4fb1ccef..001c89b7d7 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 27a300d645..b27050ec60 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 9e4481c3c6..0ccf1df260 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 41bd92bd0d..9027ff13b3 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 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)
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 0000000000..a3f3284b98
--- /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 */
+
+