1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Michael Sevakis 2007-06-05 07:03:30 +00:00
parent fea88888f0
commit bcb8a884ee
12 changed files with 559 additions and 133 deletions

View file

@ -201,6 +201,24 @@ static const struct button_mapping button_context_pitchscreen[] = {
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
}; /* button_context_pitchscreen */ }; /* 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[] = { static const struct button_mapping button_context_keyboard[] = {
{ ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE }, { ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE },
{ ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, 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; return button_context_quickscreen;
case CONTEXT_PITCHSCREEN: case CONTEXT_PITCHSCREEN:
return button_context_pitchscreen; return button_context_pitchscreen;
case CONTEXT_RECSCREEN:
return button_context_recscreen;
case CONTEXT_KEYBOARD: case CONTEXT_KEYBOARD:
return button_context_keyboard; return button_context_keyboard;

View file

@ -792,15 +792,21 @@ const struct settings_list settings[] = {
{F_T_INT|F_RECSETTING,&global_settings.cliplight,LANG_CLIP_LIGHT,INT(0), {F_T_INT|F_RECSETTING,&global_settings.cliplight,LANG_CLIP_LIGHT,INT(0),
"cliplight","off,main,both,remote",UNUSED}, "cliplight","off,main,both,remote",UNUSED},
#endif #endif
#ifdef DEFAULT_REC_MIC_GAIN
{F_T_INT|F_RECSETTING,&global_settings.rec_mic_gain, {F_T_INT|F_RECSETTING,&global_settings.rec_mic_gain,
LANG_RECORDING_GAIN,INT(DEFAULT_REC_MIC_GAIN), LANG_RECORDING_GAIN,INT(DEFAULT_REC_MIC_GAIN),
"rec mic gain",NULL,UNUSED}, "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, {F_T_INT|F_RECSETTING,&global_settings.rec_left_gain,
LANG_RECORDING_LEFT,INT(DEFAULT_REC_LEFT_GAIN), LANG_RECORDING_LEFT,INT(DEFAULT_REC_LEFT_GAIN),
"rec left gain",NULL,UNUSED}, "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, {F_T_INT|F_RECSETTING,&global_settings.rec_right_gain,LANG_RECORDING_RIGHT,
INT(DEFAULT_REC_RIGHT_GAIN), INT(DEFAULT_REC_RIGHT_GAIN),
"rec right gain",NULL,UNUSED}, "rec right gain",NULL,UNUSED},
#endif /* DEFAULT_REC_RIGHT_GAIN */
#if CONFIG_CODEC == MAS3587F #if CONFIG_CODEC == MAS3587F
{F_T_INT|F_RECSETTING,&global_settings.rec_frequency, {F_T_INT|F_RECSETTING,&global_settings.rec_frequency,
LANG_RECORDING_FREQUENCY, LANG_RECORDING_FREQUENCY,

View file

@ -296,7 +296,9 @@ target/arm/system-pp502x.c
target/arm/crt0-pp-bl.S target/arm/crt0-pp-bl.S
#else #else
target/arm/pcm-pp.c target/arm/pcm-pp.c
#ifndef SANSA_E200
target/arm/audio-pp.c target/arm/audio-pp.c
#endif /* SANSA_E200 */
target/arm/crt0-pp.S target/arm/crt0-pp.S
#endif #endif
#elif CONFIG_CPU == PNX0101 #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/button-e200.c
target/arm/sandisk/sansa-e200/power-e200.c target/arm/sandisk/sansa-e200/power-e200.c
target/arm/i2s-pp.c target/arm/i2s-pp.c
#ifndef BOOTLOADER
target/arm/sandisk/sansa-e200/audio-e200.c
#endif /* BOOTLOADER */
#endif /* SIMULATOR */ #endif /* SIMULATOR */
#endif /* SANSA_E200 */ #endif /* SANSA_E200 */

View file

@ -22,6 +22,7 @@
#include "cpu.h" #include "cpu.h"
#include "debug.h" #include "debug.h"
#include "system.h" #include "system.h"
#include "audio.h"
#include "audiohw.h" #include "audiohw.h"
#include "i2s.h" #include "i2s.h"
@ -35,33 +36,62 @@ const struct sound_settings_info audiohw_settings[] = {
[SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
[SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
[SOUND_STEREO_WIDTH] = {"%", 0, 1, 0, 255, 100}, [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 */ /* 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. * 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. * 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) 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 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 */ /* convert tenth of dB volume to master volume register value */
int tenthdb2master(int db) 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); void audiohw_reset(void);
/* /*
@ -110,20 +160,33 @@ int audiohw_init(void)
i2s_reset(); i2s_reset();
/* Set ADC off, mixer on, DAC on, line out off, line in off, mic off */ /* 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*/ /* Turn on SUM, DAC */
as3514_write(HPH_OUT_R, 0xc0 | 0x16); /* set vol and set speaker over-current to 0 */ as3514_write(AUDIOSET1, (1 << 6) | (1 << 5));
as3514_write(HPH_OUT_L, 0x16); /* set default vol for headphone */
#if 0 /* Set HPCM off, ZCU off*/
as3514_write(LINE_IN1_R, 0x36); /* unmute lineIn 1 and set gain */ as3514_write(AUDIOSET3, (1 << 2) | (1 << 0));
as3514_write(LINE_IN1_L, 0x36); /* unmute lineIn 1 and set gain */
#endif /* 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); 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 */ /* 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; return 0;
@ -136,75 +199,80 @@ void audiohw_postinit(void)
/* Silently enable / disable audio output */ /* Silently enable / disable audio output */
void audiohw_enable_output(bool enable) void audiohw_enable_output(bool enable)
{ {
int curr; if (enable) {
curr = as3514_regs[HPH_OUT_L];
if (enable)
{
/* reset the I2S controller into known state */ /* reset the I2S controller into known state */
i2s_reset(); i2s_reset();
as3514_write(HPH_OUT_L, curr | 0x40); /* power on */ as3514_write_or(HPH_OUT_L, (1 << 6)); /* power on */
audiohw_mute(0); audiohw_mute(0);
} else { } else {
audiohw_mute(1); 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 audiohw_set_master_vol(int vol_l, int vol_r)
{ {
int hph_r = as3514_regs[HPH_OUT_R] & ~0x1f; unsigned int hph_r = as3514.regs[HPH_OUT_R] & ~0x1f;
int hph_l = as3514_regs[HPH_OUT_L] & ~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;
/* we are controling dac volume instead of headphone volume, /* keep track of current setting */
as the volume is bigger. as3514.vol_l = vol_l;
HDP: 1.07 dB gain as3514.vol_r = vol_r;
DAC: 6 dB gain
*/ if (source == SOURCE_LINE_IN1_ANALOG) {
if(vol_r <= 0x16) mix_reg_r = LINE_IN1_R;
{ mix_reg_l = LINE_IN1_L;
as3514_write(DAC_R, vol_r); } else {
as3514_write(HPH_OUT_R, hph_r); /* set 0 */ mix_reg_r = DAC_R;
} mix_reg_l = DAC_L;
else
{
as3514_write(DAC_R, 0x16);
as3514_write(HPH_OUT_R, hph_r + (vol_r - 0x16));
} }
if(vol_l <= 0x16) mix_r = as3514.regs[mix_reg_r] & ~0x1f;
{ mix_l = as3514.regs[mix_reg_l] & ~0x1f;
as3514_write(DAC_L, 0x40 + vol_l);
as3514_write(HPH_OUT_L, hph_l); /* set 0 */ /* 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
{ if (vol_l <= 0x16) {
as3514_write(DAC_L, 0x40 + 0x16); mix_l |= vol_l;
as3514_write(HPH_OUT_L, hph_l + (vol_l - 0x16)); /* 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; return 0;
} }
int audiohw_set_lineout_vol(int vol_l, int vol_r) int audiohw_set_lineout_vol(int vol_l, int vol_r)
{ {
as3514_write(LINE_OUT_R, 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; return 0;
} }
int audiohw_mute(int mute) int audiohw_mute(int mute)
{ {
int curr; if (mute) {
curr = as3514_regs[HPH_OUT_L]; as3514_write_or(HPH_OUT_L, (1 << 7));
if (mute)
{
as3514_write(HPH_OUT_L, curr | 0x80);
} else { } else {
as3514_write(HPH_OUT_L, curr & ~(0x80)); as3514_write_and(HPH_OUT_L, ~(1 << 7));
} }
return 0; return 0;
@ -214,7 +282,7 @@ int audiohw_mute(int mute)
void audiohw_close(void) void audiohw_close(void)
{ {
/* mute headphones */ /* mute headphones */
audiohw_mute(1); audiohw_mute(true);
/* turn off everything */ /* turn off everything */
as3514_write(AUDIOSET1, 0x0); as3514_write(AUDIOSET1, 0x0);
@ -227,21 +295,124 @@ void audiohw_set_sample_rate(int sampling_control)
void audiohw_enable_recording(bool source_mic) 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) 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 audiohw_set_recvol(int left, int right, int type)
{ {
(void)left; switch (type)
(void)right; {
(void)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 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);
} }

View file

@ -139,6 +139,9 @@ enum audio_sources
AUDIO_SRC_DEFAULT = AUDIO_SRC_PLAYBACK AUDIO_SRC_DEFAULT = AUDIO_SRC_PLAYBACK
}; };
extern int audio_channels;
extern int audio_output_source;
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
/* Recordable source implies it has the input as well */ /* Recordable source implies it has the input as well */

View file

@ -58,7 +58,8 @@ enum {
SOUND_SUPERBASS, SOUND_SUPERBASS,
#endif #endif
#if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320)\ #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_LEFT_GAIN,
SOUND_RIGHT_GAIN, SOUND_RIGHT_GAIN,
SOUND_MIC_GAIN, SOUND_MIC_GAIN,

View file

@ -7,11 +7,22 @@
#define MODEL_NUMBER 16 #define MODEL_NUMBER 16
#define MODEL_NAME "Sandisk Sansa e200" #define MODEL_NAME "Sandisk Sansa e200"
#define HW_SAMPR_CAPS (SAMPR_CAP_44)
/* define this if you have recording possibility */ /* 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 /* Define bitmask of input sources - recordable bitmask can be defined
explicitly if different */ 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 this if you have a bitmap LCD display */
#define HAVE_LCD_BITMAP #define HAVE_LCD_BITMAP

View file

@ -292,18 +292,13 @@ enum rec_freq_indexes
#define REC_HAVE_8_(...) #define REC_HAVE_8_(...)
#endif #endif
REC_NUM_FREQ, 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 */ }; /* 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") \ #define REC_FREQ_CFG_VAL_LIST &REC_HAVE_96_(",96") REC_HAVE_88_(",88") \
REC_HAVE_64_(",64") REC_HAVE_48_(",48") \ REC_HAVE_64_(",64") REC_HAVE_48_(",48") \
REC_HAVE_44_(",44") REC_HAVE_32_(",32") \ REC_HAVE_44_(",44") REC_HAVE_32_(",32") \

View file

@ -743,6 +743,7 @@ void sound_set(int setting, int value)
sound_set_val(value); sound_set_val(value);
} }
#ifndef HAVE_AS3514
int sound_val2phys(int setting, int value) int sound_val2phys(int setting, int value)
{ {
#if CONFIG_CODEC == MAS3587F #if CONFIG_CODEC == MAS3587F
@ -804,6 +805,7 @@ int sound_val2phys(int setting, int value)
return value; return value;
#endif #endif
} }
#endif /* HAVE_AS3514 */
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
#ifndef SIMULATOR #ifndef SIMULATOR

View file

@ -160,7 +160,7 @@ void fiq(void)
{ {
/* Clear interrupt */ /* Clear interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
IISCONFIG &= ~0x2; IISCONFIG &= ~(1 << 1);
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
inl(0xcf001040); inl(0xcf001040);
IISFIFO_CFG &= ~(1<<9); IISFIFO_CFG &= ~(1<<9);
@ -171,7 +171,7 @@ void fiq(void)
if (FIFO_FREE_COUNT < 2) { if (FIFO_FREE_COUNT < 2) {
/* Enable interrupt */ /* Enable interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
IISCONFIG |= 0x2; IISCONFIG |= (1 << 1);
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
IISFIFO_CFG |= (1<<9); IISFIFO_CFG |= (1<<9);
#endif #endif
@ -221,7 +221,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
/* Enable playback FIFO */ /* Enable playback FIFO */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
IISCONFIG |= 0x20000000; IISCONFIG |= (1 << 29);
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
IISCONFIG |= 0x4; IISCONFIG |= 0x4;
#endif #endif
@ -232,7 +232,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
if (FIFO_FREE_COUNT < 2) { if (FIFO_FREE_COUNT < 2) {
/* Enable interrupt */ /* Enable interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
IISCONFIG |= 0x2; IISCONFIG |= (1 << 1);
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
IISFIFO_CFG |= (1<<9); IISFIFO_CFG |= (1<<9);
#endif #endif
@ -257,13 +257,8 @@ void pcm_play_dma_stop(void)
pcm_paused = false; pcm_paused = false;
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
/* Disable playback FIFO and interrupt */
/* Disable playback FIFO */ IISCONFIG &= ~((1 << 29) | (1 << 1));
IISCONFIG &= ~0x20000000;
/* Disable the interrupt */
IISCONFIG &= ~0x2;
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
/* Disable playback FIFO */ /* Disable playback FIFO */
@ -279,10 +274,8 @@ void pcm_play_dma_stop(void)
void pcm_play_pause_pause(void) void pcm_play_pause_pause(void)
{ {
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
/* Disable the interrupt */ /* Disable playback FIFO and interrupt */
IISCONFIG &= ~0x2; IISCONFIG &= ~((1 << 29) | (1 << 1));
/* Disable playback FIFO */
IISCONFIG &= ~0x20000000;
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
/* Disable the interrupt */ /* Disable the interrupt */
IISFIFO_CFG &= ~(1<<9); IISFIFO_CFG &= ~(1<<9);
@ -301,7 +294,7 @@ void pcm_play_pause_unpause(void)
/* Enable playback FIFO */ /* Enable playback FIFO */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
IISCONFIG |= 0x20000000; IISCONFIG |= (1 << 29);
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
IISCONFIG |= 0x4; IISCONFIG |= 0x4;
#endif #endif
@ -312,7 +305,7 @@ void pcm_play_pause_unpause(void)
if (FIFO_FREE_COUNT < 2) { if (FIFO_FREE_COUNT < 2) {
/* Enable interrupt */ /* Enable interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
IISCONFIG |= 0x2; IISCONFIG |= (1 << 1);
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
IISFIFO_CFG |= (1<<9); IISFIFO_CFG |= (1<<9);
#endif #endif
@ -369,6 +362,79 @@ void pcm_postinit(void)
** Recording DMA transfer ** Recording DMA transfer
**/ **/
#ifdef HAVE_RECORDING #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; static short peak_l, peak_r IBSS_ATTR;
void fiq_record(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); void fiq_record(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
@ -380,7 +446,7 @@ void fiq_record(void)
/* Clear interrupt */ /* Clear interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
IISCONFIG &= ~0x01; IISCONFIG &= ~(1 << 0);
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
/* TODO */ /* TODO */
#endif #endif
@ -389,12 +455,13 @@ void fiq_record(void)
if (FIFO_FREE_COUNT < 2) { if (FIFO_FREE_COUNT < 2) {
/* enable interrupt */ /* enable interrupt */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
IISCONFIG |= 0x01; IISCONFIG |= (1 << 0);
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
/* TODO */ /* TODO */
#endif #endif
return; return;
} }
value = (unsigned short)(IISFIFO_RD >> 16); value = (unsigned short)(IISFIFO_RD >> 16);
if (value > peak_l) peak_l = value; if (value > peak_l) peak_l = value;
else if (-value > peak_l) peak_l = -value; else if (-value > peak_l) peak_l = -value;
@ -424,14 +491,16 @@ void fiq_record(void)
pcm_rec_dma_stop(); pcm_rec_dma_stop();
} }
#endif /* HAVE_AS3514 */
/* Continue transferring data in */ /* Continue transferring data in */
void pcm_record_more(void *start, size_t size) void pcm_record_more(void *start, size_t size)
{ {
rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */ rec_peak_addr = start; /* Start peaking at dest */
p = start; p = start; /* Start of RX buffer */
p_size = size; /* Bytes to transfer */ p_size = size; /* Bytes to transfer */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024
IISCONFIG |= 0x01; IISCONFIG |= (1 << 0);
#elif CONFIG_CPU == PP5002 #elif CONFIG_CPU == PP5002
/* TODO */ /* TODO */
#endif #endif
@ -441,11 +510,14 @@ void pcm_rec_dma_stop(void)
{ {
logf("pcm_rec_dma_stop"); logf("pcm_rec_dma_stop");
/* disable fifo */
IISCONFIG &= ~0x10000000;
disable_fiq(); disable_fiq();
/* clear interrupt, disable fifo */
IISCONFIG &= ~((1 << 28) | (1 << 0));
/* clear rx fifo */
IISFIFO_CFG |= (1 << 12);
pcm_recording = false; pcm_recording = false;
} }
@ -455,7 +527,10 @@ void pcm_rec_dma_start(void *addr, size_t size)
pcm_recording = true; pcm_recording = true;
#ifndef HAVE_AS3514
peak_l = peak_r = 0; peak_l = peak_r = 0;
#endif
p_size = size; p_size = size;
p = addr; p = addr;
@ -463,11 +538,8 @@ void pcm_rec_dma_start(void *addr, size_t size)
CPU_INT_PRIORITY |= I2S_MASK; CPU_INT_PRIORITY |= I2S_MASK;
CPU_INT_EN = I2S_MASK; CPU_INT_EN = I2S_MASK;
/* interrupt on full fifo */ /* interrupt on full fifo, enable record fifo */
IISCONFIG |= 0x1; IISCONFIG |= (1 << 28) | (1 << 0);
/* enable record fifo */
IISCONFIG |= 0x10000000;
set_fiq_handler(fiq_record); set_fiq_handler(fiq_record);
enable_fiq(); enable_fiq();
@ -476,18 +548,7 @@ void pcm_rec_dma_start(void *addr, size_t size)
void pcm_close_recording(void) void pcm_close_recording(void)
{ {
logf("pcm_close_recording"); logf("pcm_close_recording");
pcm_rec_dma_stop(); 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 */ } /* pcm_close_recording */
void pcm_init_recording(void) void pcm_init_recording(void)
@ -505,7 +566,7 @@ void pcm_init_recording(void)
GPIOA_OUTPUT_VAL &= ~0x4; GPIOA_OUTPUT_VAL &= ~0x4;
#endif #endif
/* Setup the recording FIQ handler */ /* Setup the recording FIQ handler */
*((unsigned int*)(15*4)) = (unsigned int)&fiq_record; set_fiq_handler(fiq_record);
#endif #endif
pcm_rec_dma_stop(); pcm_rec_dma_stop();
@ -513,10 +574,57 @@ void pcm_init_recording(void)
void pcm_calculate_rec_peaks(int *left, int *right) void pcm_calculate_rec_peaks(int *left, int *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; *left = rec_peak_left;
if (right)
*right = rec_peak_right; *right = rec_peak_right;
} }
#endif #endif /* HAVE_RECORDING */
/* /*
* This function goes directly into the DMA buffer to calculate the left and * This function goes directly into the DMA buffer to calculate the left and

View file

@ -223,6 +223,7 @@ void sd_wait_for_state(tSDCardInfo* card, unsigned int state)
while(((response >> 9) & 0xf) != state) while(((response >> 9) & 0xf) != state)
{ {
sd_send_command(SEND_STATUS, (card->rca) << 16, 1); sd_send_command(SEND_STATUS, (card->rca) << 16, 1);
priority_yield();
sd_read_response(&response, 1); sd_read_response(&response, 1);
/* TODO: Add a timeout and error handling */ /* 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 */ dataptr += (FIFO_SIZE*2); /* Advance one chunk of 16 words */
} }
} }
mutex_init(&sd_mtx); spinlock_init(&sd_mtx);
} }
/* API Functions */ /* API Functions */
@ -472,7 +473,7 @@ int ata_read_sectors(IF_MV2(int drive,)
#ifdef HAVE_MULTIVOLUME #ifdef HAVE_MULTIVOLUME
(void)drive; /* unused for now */ (void)drive; /* unused for now */
#endif #endif
mutex_lock(&sd_mtx); spinlock_lock(&sd_mtx);
last_disk_activity = current_tick; last_disk_activity = current_tick;
spinup_start = current_tick; spinup_start = current_tick;
@ -530,7 +531,7 @@ int ata_read_sectors(IF_MV2(int drive,)
ata_led(false); ata_led(false);
ata_enable(false); ata_enable(false);
mutex_unlock(&sd_mtx); spinlock_unlock(&sd_mtx);
return ret; return ret;
} }
@ -551,7 +552,7 @@ int ata_write_sectors(IF_MV2(int drive,)
long timeout; long timeout;
tSDCardInfo *card = &card_info[current_card]; tSDCardInfo *card = &card_info[current_card];
mutex_lock(&sd_mtx); spinlock_lock(&sd_mtx);
ata_enable(true); ata_enable(true);
ata_led(true); ata_led(true);
if(current_card == 0) if(current_card == 0)
@ -607,7 +608,7 @@ retry:
sd_wait_for_state(card, TRAN); sd_wait_for_state(card, TRAN);
ata_led(false); ata_led(false);
ata_enable(false); ata_enable(false);
mutex_unlock(&sd_mtx); spinlock_unlock(&sd_mtx);
return ret; return ret;
} }

View file

@ -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 */