forked from len0rd/rockbox
Gigabeat S: Allow recording from FM. Give FM the same volume range as playback. NOTE: This bumps the si4700 output volume to -0dB so other players with that may need a minor adjustment.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19619 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
9ac7af749b
commit
2e99b3d931
10 changed files with 454 additions and 166 deletions
|
@ -251,6 +251,23 @@ static const struct button_mapping button_context_pitchscreen[] = {
|
||||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
||||||
}; /* button_context_pitchcreen */
|
}; /* button_context_pitchcreen */
|
||||||
|
|
||||||
|
/** Recording Screen **/
|
||||||
|
static const struct button_mapping button_context_recscreen[] = {
|
||||||
|
{ ACTION_REC_PAUSE, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY },
|
||||||
|
{ ACTION_STD_CANCEL, BUTTON_BACK|BUTTON_REL, BUTTON_BACK },
|
||||||
|
{ ACTION_REC_NEWFILE, BUTTON_NEXT|BUTTON_REL, BUTTON_NEXT },
|
||||||
|
{ ACTION_STD_MENU, BUTTON_MENU|BUTTON_REPEAT, BUTTON_NONE },
|
||||||
|
{ ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE },
|
||||||
|
{ ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
|
||||||
|
{ ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE },
|
||||||
|
{ ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
|
||||||
|
{ ACTION_STD_PREV, BUTTON_UP, BUTTON_NONE },
|
||||||
|
{ ACTION_STD_PREV, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
|
||||||
|
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
|
||||||
|
{ ACTION_STD_NEXT, BUTTON_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 },
|
||||||
|
@ -333,6 +350,10 @@ 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_SETTINGS_RECTRIGGER:
|
||||||
|
return button_context_settings_right_is_inc;
|
||||||
case CONTEXT_KEYBOARD:
|
case CONTEXT_KEYBOARD:
|
||||||
return button_context_keyboard;
|
return button_context_keyboard;
|
||||||
case CONTEXT_FM:
|
case CONTEXT_FM:
|
||||||
|
|
|
@ -274,12 +274,14 @@ static short agc_maxgain;
|
||||||
|
|
||||||
static void set_gain(void)
|
static void set_gain(void)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
if(global_settings.rec_source == AUDIO_SRC_MIC)
|
if(global_settings.rec_source == AUDIO_SRC_MIC)
|
||||||
{
|
{
|
||||||
audio_set_recording_gain(global_settings.rec_mic_gain,
|
audio_set_recording_gain(global_settings.rec_mic_gain,
|
||||||
0, AUDIO_GAIN_MIC);
|
0, AUDIO_GAIN_MIC);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif /* MIC */
|
||||||
{
|
{
|
||||||
/* AUDIO_SRC_LINEIN, AUDIO_SRC_FMRADIO, AUDIO_SRC_SPDIF */
|
/* AUDIO_SRC_LINEIN, AUDIO_SRC_FMRADIO, AUDIO_SRC_SPDIF */
|
||||||
audio_set_recording_gain(global_settings.rec_left_gain,
|
audio_set_recording_gain(global_settings.rec_left_gain,
|
||||||
|
@ -332,15 +334,19 @@ static bool agc_gain_is_max(bool left, bool right)
|
||||||
|
|
||||||
switch (global_settings.rec_source)
|
switch (global_settings.rec_source)
|
||||||
{
|
{
|
||||||
|
#if defined(HAVE_LINE_REC) || defined(HAVE_FMRADIO_REC)
|
||||||
HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:)
|
HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:)
|
||||||
HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:)
|
HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:)
|
||||||
gain_current_l = global_settings.rec_left_gain;
|
gain_current_l = global_settings.rec_left_gain;
|
||||||
gain_current_r = global_settings.rec_right_gain;
|
gain_current_r = global_settings.rec_right_gain;
|
||||||
break;
|
break;
|
||||||
|
#endif /* LINE, FMRADIO */
|
||||||
|
#if defined(HAVE_MIC_REC)
|
||||||
case AUDIO_SRC_MIC:
|
case AUDIO_SRC_MIC:
|
||||||
default:
|
default:
|
||||||
gain_current_l = global_settings.rec_mic_gain;
|
gain_current_l = global_settings.rec_mic_gain;
|
||||||
gain_current_r = global_settings.rec_mic_gain;
|
gain_current_r = global_settings.rec_mic_gain;
|
||||||
|
#endif /* MIC */
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((left && (gain_current_l >= agc_maxgain)) ||
|
return ((left && (gain_current_l >= agc_maxgain)) ||
|
||||||
|
@ -353,13 +359,17 @@ static void change_recording_gain(bool increment, bool left, bool right)
|
||||||
|
|
||||||
switch (global_settings.rec_source)
|
switch (global_settings.rec_source)
|
||||||
{
|
{
|
||||||
|
#if defined(HAVE_LINE_REC) || defined(HAVE_FMRADIO_REC)
|
||||||
HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:)
|
HAVE_LINE_REC_(case AUDIO_SRC_LINEIN:)
|
||||||
HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:)
|
HAVE_FMRADIO_REC_(case AUDIO_SRC_FMRADIO:)
|
||||||
if (left) global_settings.rec_left_gain += factor;
|
if (left) global_settings.rec_left_gain += factor;
|
||||||
if (right) global_settings.rec_right_gain += factor;
|
if (right) global_settings.rec_right_gain += factor;
|
||||||
break;
|
break;
|
||||||
|
#endif /* LINE, FMRADIO */
|
||||||
|
#if defined(HAVE_MIC_REC)
|
||||||
case AUDIO_SRC_MIC:
|
case AUDIO_SRC_MIC:
|
||||||
global_settings.rec_mic_gain += factor;
|
global_settings.rec_mic_gain += factor;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,6 +868,7 @@ static char * reclist_get_name(int selected_item, void * data,
|
||||||
buf2, sizeof(buf2)));
|
buf2, sizeof(buf2)));
|
||||||
break;
|
break;
|
||||||
case ITEM_GAIN:
|
case ITEM_GAIN:
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
if(global_settings.rec_source == AUDIO_SRC_MIC)
|
if(global_settings.rec_source == AUDIO_SRC_MIC)
|
||||||
{
|
{
|
||||||
/* Draw MIC recording gain */
|
/* Draw MIC recording gain */
|
||||||
|
@ -867,6 +878,7 @@ static char * reclist_get_name(int selected_item, void * data,
|
||||||
buf2, sizeof(buf2)));
|
buf2, sizeof(buf2)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif /* MIC */
|
||||||
{
|
{
|
||||||
int avg_gain = (global_settings.rec_left_gain +
|
int avg_gain = (global_settings.rec_left_gain +
|
||||||
global_settings.rec_right_gain) / 2;
|
global_settings.rec_right_gain) / 2;
|
||||||
|
@ -902,6 +914,7 @@ static char * reclist_get_name(int selected_item, void * data,
|
||||||
str(LANG_RECORDING_AGC_MAXGAIN),
|
str(LANG_RECORDING_AGC_MAXGAIN),
|
||||||
fmt_gain(SOUND_LEFT_GAIN,
|
fmt_gain(SOUND_LEFT_GAIN,
|
||||||
agc_maxgain, buf2, sizeof(buf2)));
|
agc_maxgain, buf2, sizeof(buf2)));
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
else if (global_settings.rec_source == AUDIO_SRC_MIC)
|
else if (global_settings.rec_source == AUDIO_SRC_MIC)
|
||||||
snprintf(buffer, buffer_len, "%s: %s (%s)",
|
snprintf(buffer, buffer_len, "%s: %s (%s)",
|
||||||
str(LANG_RECORDING_AGC_MAXGAIN),
|
str(LANG_RECORDING_AGC_MAXGAIN),
|
||||||
|
@ -911,6 +924,7 @@ static char * reclist_get_name(int selected_item, void * data,
|
||||||
agc_maxgain - global_settings.rec_mic_gain,
|
agc_maxgain - global_settings.rec_mic_gain,
|
||||||
buf3, sizeof(buf3)));
|
buf3, sizeof(buf3)));
|
||||||
else
|
else
|
||||||
|
#endif /* MIC */
|
||||||
snprintf(buffer, buffer_len, "%s: %s (%s)",
|
snprintf(buffer, buffer_len, "%s: %s (%s)",
|
||||||
str(LANG_RECORDING_AGC_MAXGAIN),
|
str(LANG_RECORDING_AGC_MAXGAIN),
|
||||||
fmt_gain(SOUND_LEFT_GAIN,
|
fmt_gain(SOUND_LEFT_GAIN,
|
||||||
|
@ -1180,15 +1194,18 @@ bool recording_screen(bool no_source)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_AGC
|
#ifdef HAVE_AGC
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
if (global_settings.rec_source == AUDIO_SRC_MIC) {
|
if (global_settings.rec_source == AUDIO_SRC_MIC) {
|
||||||
agc_preset = global_settings.rec_agc_preset_mic;
|
agc_preset = global_settings.rec_agc_preset_mic;
|
||||||
agc_maxgain = global_settings.rec_agc_maxgain_mic;
|
agc_maxgain = global_settings.rec_agc_maxgain_mic;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif /* MIC */
|
||||||
|
{
|
||||||
agc_preset = global_settings.rec_agc_preset_line;
|
agc_preset = global_settings.rec_agc_preset_line;
|
||||||
agc_maxgain = global_settings.rec_agc_maxgain_line;
|
agc_maxgain = global_settings.rec_agc_maxgain_line;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* HAVE_AGC */
|
||||||
|
|
||||||
set_gain();
|
set_gain();
|
||||||
update_countdown = 0; /* Update immediately */
|
update_countdown = 0; /* Update immediately */
|
||||||
|
@ -1209,7 +1226,7 @@ bool recording_screen(bool no_source)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
if((global_settings.rec_source == AUDIO_SRC_MIC) ||
|
if(HAVE_MIC_REC_((global_settings.rec_source == AUDIO_SRC_MIC) || )
|
||||||
(global_settings.rec_channels == 1))
|
(global_settings.rec_channels == 1))
|
||||||
{
|
{
|
||||||
listid_to_enum[0] = ITEM_VOLUME_M;
|
listid_to_enum[0] = ITEM_VOLUME_M;
|
||||||
|
@ -1335,6 +1352,7 @@ bool recording_screen(bool no_source)
|
||||||
setvol();
|
setvol();
|
||||||
break;
|
break;
|
||||||
case ITEM_GAIN:
|
case ITEM_GAIN:
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
if(global_settings.rec_source == AUDIO_SRC_MIC)
|
if(global_settings.rec_source == AUDIO_SRC_MIC)
|
||||||
{
|
{
|
||||||
if(global_settings.rec_mic_gain <
|
if(global_settings.rec_mic_gain <
|
||||||
|
@ -1342,6 +1360,7 @@ bool recording_screen(bool no_source)
|
||||||
global_settings.rec_mic_gain++;
|
global_settings.rec_mic_gain++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif /* MIC */
|
||||||
{
|
{
|
||||||
if(global_settings.rec_left_gain <
|
if(global_settings.rec_left_gain <
|
||||||
sound_max(SOUND_LEFT_GAIN))
|
sound_max(SOUND_LEFT_GAIN))
|
||||||
|
@ -1365,15 +1384,19 @@ bool recording_screen(bool no_source)
|
||||||
case ITEM_AGC_MODE:
|
case ITEM_AGC_MODE:
|
||||||
agc_preset = MIN(agc_preset + 1, AGC_MODE_SIZE);
|
agc_preset = MIN(agc_preset + 1, AGC_MODE_SIZE);
|
||||||
agc_enable = (agc_preset != 0);
|
agc_enable = (agc_preset != 0);
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
if (global_settings.rec_source == AUDIO_SRC_MIC) {
|
if (global_settings.rec_source == AUDIO_SRC_MIC) {
|
||||||
global_settings.rec_agc_preset_mic = agc_preset;
|
global_settings.rec_agc_preset_mic = agc_preset;
|
||||||
agc_maxgain = global_settings.rec_agc_maxgain_mic;
|
agc_maxgain = global_settings.rec_agc_maxgain_mic;
|
||||||
} else {
|
} else
|
||||||
|
#endif /* MIC */
|
||||||
|
{
|
||||||
global_settings.rec_agc_preset_line = agc_preset;
|
global_settings.rec_agc_preset_line = agc_preset;
|
||||||
agc_maxgain = global_settings.rec_agc_maxgain_line;
|
agc_maxgain = global_settings.rec_agc_maxgain_line;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ITEM_AGC_MAXDB:
|
case ITEM_AGC_MAXDB:
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
if (global_settings.rec_source == AUDIO_SRC_MIC)
|
if (global_settings.rec_source == AUDIO_SRC_MIC)
|
||||||
{
|
{
|
||||||
agc_maxgain = MIN(agc_maxgain + 1,
|
agc_maxgain = MIN(agc_maxgain + 1,
|
||||||
|
@ -1381,6 +1404,7 @@ bool recording_screen(bool no_source)
|
||||||
global_settings.rec_agc_maxgain_mic = agc_maxgain;
|
global_settings.rec_agc_maxgain_mic = agc_maxgain;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif /* MIC */
|
||||||
{
|
{
|
||||||
agc_maxgain = MIN(agc_maxgain + 1,
|
agc_maxgain = MIN(agc_maxgain + 1,
|
||||||
sound_max(SOUND_LEFT_GAIN));
|
sound_max(SOUND_LEFT_GAIN));
|
||||||
|
@ -1401,6 +1425,7 @@ bool recording_screen(bool no_source)
|
||||||
setvol();
|
setvol();
|
||||||
break;
|
break;
|
||||||
case ITEM_GAIN:
|
case ITEM_GAIN:
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
if(global_settings.rec_source == AUDIO_SRC_MIC)
|
if(global_settings.rec_source == AUDIO_SRC_MIC)
|
||||||
{
|
{
|
||||||
if(global_settings.rec_mic_gain >
|
if(global_settings.rec_mic_gain >
|
||||||
|
@ -1408,6 +1433,7 @@ bool recording_screen(bool no_source)
|
||||||
global_settings.rec_mic_gain--;
|
global_settings.rec_mic_gain--;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif /* MIC */
|
||||||
{
|
{
|
||||||
if(global_settings.rec_left_gain >
|
if(global_settings.rec_left_gain >
|
||||||
sound_min(SOUND_LEFT_GAIN))
|
sound_min(SOUND_LEFT_GAIN))
|
||||||
|
@ -1431,22 +1457,26 @@ bool recording_screen(bool no_source)
|
||||||
case ITEM_AGC_MODE:
|
case ITEM_AGC_MODE:
|
||||||
agc_preset = MAX(agc_preset - 1, 0);
|
agc_preset = MAX(agc_preset - 1, 0);
|
||||||
agc_enable = (agc_preset != 0);
|
agc_enable = (agc_preset != 0);
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
if (global_settings.rec_source == AUDIO_SRC_MIC) {
|
if (global_settings.rec_source == AUDIO_SRC_MIC) {
|
||||||
global_settings.rec_agc_preset_mic = agc_preset;
|
global_settings.rec_agc_preset_mic = agc_preset;
|
||||||
agc_maxgain = global_settings.rec_agc_maxgain_mic;
|
agc_maxgain = global_settings.rec_agc_maxgain_mic;
|
||||||
} else {
|
} else
|
||||||
|
#endif /* MIC */
|
||||||
|
{
|
||||||
global_settings.rec_agc_preset_line = agc_preset;
|
global_settings.rec_agc_preset_line = agc_preset;
|
||||||
agc_maxgain = global_settings.rec_agc_maxgain_line;
|
agc_maxgain = global_settings.rec_agc_maxgain_line;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ITEM_AGC_MAXDB:
|
case ITEM_AGC_MAXDB:
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
if (global_settings.rec_source == AUDIO_SRC_MIC)
|
if (global_settings.rec_source == AUDIO_SRC_MIC)
|
||||||
{
|
{
|
||||||
agc_maxgain = MAX(agc_maxgain - 1,
|
agc_maxgain = MAX(agc_maxgain - 1,
|
||||||
sound_min(SOUND_MIC_GAIN));
|
sound_min(SOUND_MIC_GAIN));
|
||||||
global_settings.rec_agc_maxgain_mic = agc_maxgain;
|
global_settings.rec_agc_maxgain_mic = agc_maxgain;
|
||||||
}
|
} else
|
||||||
else
|
#endif /* MIC */
|
||||||
{
|
{
|
||||||
agc_maxgain = MAX(agc_maxgain - 1,
|
agc_maxgain = MAX(agc_maxgain - 1,
|
||||||
sound_min(SOUND_LEFT_GAIN));
|
sound_min(SOUND_LEFT_GAIN));
|
||||||
|
@ -1796,12 +1826,14 @@ bool recording_screen(bool no_source)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_AGC
|
#ifdef HAVE_AGC
|
||||||
|
#ifdef HAVE_MIC_REC
|
||||||
if (global_settings.rec_source == AUDIO_SRC_MIC)
|
if (global_settings.rec_source == AUDIO_SRC_MIC)
|
||||||
{
|
{
|
||||||
if(agc_maxgain < (global_settings.rec_mic_gain))
|
if(agc_maxgain < (global_settings.rec_mic_gain))
|
||||||
change_recording_gain(false, true, true);
|
change_recording_gain(false, true, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif /* MIC */
|
||||||
{
|
{
|
||||||
if(agc_maxgain < (global_settings.rec_left_gain))
|
if(agc_maxgain < (global_settings.rec_left_gain))
|
||||||
change_recording_gain(false, true, false);
|
change_recording_gain(false, true, false);
|
||||||
|
|
|
@ -28,18 +28,11 @@
|
||||||
//#define LOGF_ENABLE
|
//#define LOGF_ENABLE
|
||||||
#include "logf.h"
|
#include "logf.h"
|
||||||
|
|
||||||
/* #define to help adjust lower volume limit */
|
|
||||||
#define HW_VOL_MIN 0
|
|
||||||
#define HW_VOL_MUTE 0
|
|
||||||
#define HW_VOL_MAX 96
|
|
||||||
#define HW_VOL_ANA_MIN 0
|
|
||||||
#define HW_VOL_ANA_MAX 63
|
|
||||||
#define HW_VOL_DIG_MAX 255
|
|
||||||
#define HW_VOL_DIG_THRESHOLD (HW_VOL_MAX - HW_VOL_ANA_MAX)
|
|
||||||
#define HW_VOL_DIG_MIN (HW_VOL_DIG_MAX - 2*HW_VOL_DIG_THRESHOLD)
|
|
||||||
|
|
||||||
/* TODO: Define/refine an API for special hardware steps outside the
|
/* TODO: Define/refine an API for special hardware steps outside the
|
||||||
* main codec driver such as special GPIO handling. */
|
* main codec driver such as special GPIO handling. */
|
||||||
|
/* NOTE: Much of the volume code is very interdependent and calibrated for
|
||||||
|
* the Gigabeat S. If you change anything for another device that uses this
|
||||||
|
* file it may break things. */
|
||||||
extern void audiohw_enable_headphone_jack(bool enable);
|
extern void audiohw_enable_headphone_jack(bool enable);
|
||||||
|
|
||||||
const struct sound_settings_info audiohw_settings[] =
|
const struct sound_settings_info audiohw_settings[] =
|
||||||
|
@ -51,10 +44,14 @@ const struct sound_settings_info audiohw_settings[] =
|
||||||
[SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
|
[SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
|
||||||
[SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
|
[SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
|
||||||
#ifdef HAVE_RECORDING
|
#ifdef HAVE_RECORDING
|
||||||
[SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
|
/* Digital: -119.0dB to +8.0dB in 0.5dB increments
|
||||||
[SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
|
* Analog: Relegated to volume control
|
||||||
|
* Circumstances unfortunately do not allow a great deal of positive
|
||||||
|
* gain. */
|
||||||
|
[SOUND_LEFT_GAIN] = {"dB", 1, 1,-238, 16, 0},
|
||||||
|
[SOUND_RIGHT_GAIN] = {"dB", 1, 1,-238, 16, 0},
|
||||||
#if 0
|
#if 0
|
||||||
[SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
|
[SOUND_MIC_GAIN] = {"dB", 1, 1,-238, 16, 0},
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -107,8 +104,8 @@ static uint16_t wmc_regs[WMC_NUM_REGISTERS] =
|
||||||
[WMC_3D_CONTROL] = 0x000,
|
[WMC_3D_CONTROL] = 0x000,
|
||||||
[WMC_BEEP_CONTROL] = 0x000,
|
[WMC_BEEP_CONTROL] = 0x000,
|
||||||
[WMC_INPUT_CTRL] = 0x033,
|
[WMC_INPUT_CTRL] = 0x033,
|
||||||
[WMC_LEFT_INP_PGA_GAIN_CTRL] = 0x010,
|
[WMC_LEFT_INP_PGA_GAIN_CTRL] = 0x010 | WMC_VU | WMC_ZC,
|
||||||
[WMC_RIGHT_INP_PGA_GAIN_CTRL] = 0x010,
|
[WMC_RIGHT_INP_PGA_GAIN_CTRL] = 0x010 | WMC_VU | WMC_ZC,
|
||||||
[WMC_LEFT_ADC_BOOST_CTRL] = 0x100,
|
[WMC_LEFT_ADC_BOOST_CTRL] = 0x100,
|
||||||
[WMC_RIGHT_ADC_BOOST_CTRL] = 0x100,
|
[WMC_RIGHT_ADC_BOOST_CTRL] = 0x100,
|
||||||
[WMC_OUTPUT_CTRL] = 0x002,
|
[WMC_OUTPUT_CTRL] = 0x002,
|
||||||
|
@ -129,7 +126,7 @@ struct
|
||||||
bool ahw_mute;
|
bool ahw_mute;
|
||||||
} wmc_vol =
|
} wmc_vol =
|
||||||
{
|
{
|
||||||
HW_VOL_MUTE, HW_VOL_MUTE, false
|
0, 0, false
|
||||||
};
|
};
|
||||||
|
|
||||||
static void wmc_write(unsigned int reg, unsigned int val)
|
static void wmc_write(unsigned int reg, unsigned int val)
|
||||||
|
@ -180,6 +177,27 @@ int tenthdb2master(int db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sound_val2phys(int setting, int value)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
switch (setting)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_RECORDING
|
||||||
|
case SOUND_LEFT_GAIN:
|
||||||
|
case SOUND_RIGHT_GAIN:
|
||||||
|
case SOUND_MIC_GAIN:
|
||||||
|
result = value * 5;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void audiohw_preinit(void)
|
void audiohw_preinit(void)
|
||||||
{
|
{
|
||||||
/* 1. Turn on external power supplies. Wait for supply voltage to settle. */
|
/* 1. Turn on external power supplies. Wait for supply voltage to settle. */
|
||||||
|
@ -190,13 +208,12 @@ void audiohw_preinit(void)
|
||||||
sleep(HZ/10);
|
sleep(HZ/10);
|
||||||
|
|
||||||
/* 2. Mute all analogue outputs */
|
/* 2. Mute all analogue outputs */
|
||||||
wmc_set(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE | HW_VOL_ANA_MIN);
|
wmc_set(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
||||||
wmc_set(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE | HW_VOL_ANA_MIN);
|
wmc_set(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
||||||
wmc_set(WMC_LOUT2_SPK_VOLUME_CTRL, WMC_MUTE);
|
wmc_set(WMC_LOUT2_SPK_VOLUME_CTRL, WMC_MUTE);
|
||||||
wmc_set(WMC_ROUT2_SPK_VOLUME_CTRL, WMC_MUTE);
|
wmc_set(WMC_ROUT2_SPK_VOLUME_CTRL, WMC_MUTE);
|
||||||
wmc_set(WMC_OUT3_MIXER_CTRL, WMC_MUTE);
|
wmc_set(WMC_OUT3_MIXER_CTRL, WMC_MUTE);
|
||||||
wmc_set(WMC_OUT4_MONO_MIXER_CTRL, WMC_MUTE);
|
wmc_set(WMC_OUT4_MONO_MIXER_CTRL, WMC_MUTE);
|
||||||
wmc_set(WMC_INPUT_CTRL, 0x000);
|
|
||||||
|
|
||||||
/* 3. Set L/RMIXEN = 1 and DACENL/R = 1 in register R3. */
|
/* 3. Set L/RMIXEN = 1 and DACENL/R = 1 in register R3. */
|
||||||
wmc_write(WMC_POWER_MANAGEMENT3,
|
wmc_write(WMC_POWER_MANAGEMENT3,
|
||||||
|
@ -226,103 +243,105 @@ void audiohw_postinit(void)
|
||||||
wmc_write(WMC_AUDIO_INTERFACE, WMC_WL_16 | WMC_FMT_I2S);
|
wmc_write(WMC_AUDIO_INTERFACE, WMC_WL_16 | WMC_FMT_I2S);
|
||||||
wmc_write(WMC_DAC_CONTROL, WMC_DACOSR_128 | WMC_AMUTE);
|
wmc_write(WMC_DAC_CONTROL, WMC_DACOSR_128 | WMC_AMUTE);
|
||||||
|
|
||||||
wmc_set(WMC_INPUT_CTRL, WMC_R2_2INPPGA | WMC_L2_2INPPGA);
|
/* No ADC, no HP filter, no popping */
|
||||||
/* set PGA volumes to 0dB and enable zero cross */
|
wmc_clear(WMC_ADC_CONTROL, WMC_HPFEN);
|
||||||
wmc_set(WMC_LEFT_INP_PGA_GAIN_CTRL, 0x10 | 1 << 7);
|
|
||||||
wmc_set(WMC_RIGHT_INP_PGA_GAIN_CTRL, 0x10 | 1 << 7);
|
wmc_clear(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL);
|
||||||
/* write to INPPGAUPDATE to actually change voulme */
|
wmc_clear(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR);
|
||||||
wmc_set(WMC_LEFT_INP_PGA_GAIN_CTRL, 1 << 8);
|
|
||||||
wmc_set(WMC_RIGHT_INP_PGA_GAIN_CTRL, 1 << 8);
|
|
||||||
/* set boost gain to 0dB */
|
|
||||||
wmc_set(WMC_LEFT_ADC_BOOST_CTRL, (5 << 4));
|
|
||||||
wmc_set(WMC_RIGHT_ADC_BOOST_CTRL, (5 << 4));
|
|
||||||
|
|
||||||
/* Specific to HW clocking */
|
/* Specific to HW clocking */
|
||||||
wmc_write_masked(WMC_CLOCK_GEN_CTRL, WMC_BCLKDIV_4 | WMC_MS,
|
wmc_write_masked(WMC_CLOCK_GEN_CTRL, WMC_BCLKDIV_4 | WMC_MS,
|
||||||
WMC_BCLKDIV | WMC_MS | WMC_CLKSEL);
|
WMC_BCLKDIV | WMC_MS | WMC_CLKSEL);
|
||||||
audiohw_set_frequency(HW_FREQ_DEFAULT);
|
audiohw_set_frequency(HW_FREQ_DEFAULT);
|
||||||
|
|
||||||
/* ADC silenced */
|
|
||||||
wmc_write_masked(WMC_LEFT_ADC_DIGITAL_VOL, 0x00, WMC_DVOL);
|
|
||||||
wmc_write_masked(WMC_RIGHT_ADC_DIGITAL_VOL, 0x00, WMC_DVOL);
|
|
||||||
|
|
||||||
audiohw_enable_headphone_jack(true);
|
audiohw_enable_headphone_jack(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_headphone_levels(int val, int *dac_p, int *hp_p,
|
||||||
|
int *mix_p, int *boost_p)
|
||||||
|
{
|
||||||
|
int dac, hp, mix, boost;
|
||||||
|
|
||||||
|
if (val >= 33)
|
||||||
|
{
|
||||||
|
dac = 255;
|
||||||
|
hp = val - 33;
|
||||||
|
mix = 7;
|
||||||
|
boost = 5;
|
||||||
|
}
|
||||||
|
else if (val >= 21)
|
||||||
|
{
|
||||||
|
dac = 189 + val / 3 * 6;
|
||||||
|
hp = val % 3;
|
||||||
|
mix = 7;
|
||||||
|
boost = (val - 18) / 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dac = 189 + val / 3 * 6;
|
||||||
|
hp = val % 3;
|
||||||
|
mix = val / 3;
|
||||||
|
boost = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dac_p = dac;
|
||||||
|
*hp_p = hp;
|
||||||
|
*mix_p = mix;
|
||||||
|
*boost_p = boost;
|
||||||
|
}
|
||||||
|
|
||||||
void audiohw_set_headphone_vol(int vol_l, int vol_r)
|
void audiohw_set_headphone_vol(int vol_l, int vol_r)
|
||||||
{
|
{
|
||||||
int prev_l = wmc_vol.vol_l;
|
int prev_l = wmc_vol.vol_l;
|
||||||
int prev_r = wmc_vol.vol_r;
|
int prev_r = wmc_vol.vol_r;
|
||||||
int dac_l, dac_r;
|
int dac_l, dac_r, hp_l, hp_r;
|
||||||
|
int mix_l, mix_r, boost_l, boost_r;
|
||||||
|
|
||||||
wmc_vol.vol_l = vol_l;
|
wmc_vol.vol_l = vol_l;
|
||||||
wmc_vol.vol_r = vol_r;
|
wmc_vol.vol_r = vol_r;
|
||||||
|
|
||||||
/* When analogue volume falls below -57dB (0x00) start attenuating the
|
/* Mixers are synced to provide full volume range on both the analogue
|
||||||
* DAC volume */
|
* and digital pathways */
|
||||||
if (vol_l >= HW_VOL_DIG_THRESHOLD)
|
get_headphone_levels(vol_l, &dac_l, &hp_l, &mix_l, &boost_l);
|
||||||
{
|
get_headphone_levels(vol_r, &dac_r, &hp_r, &mix_r, &boost_r);
|
||||||
if (vol_l > HW_VOL_MAX)
|
|
||||||
vol_l = HW_VOL_MAX;
|
|
||||||
|
|
||||||
dac_l = HW_VOL_DIG_MAX;
|
wmc_write_masked(WMC_LEFT_MIXER_CTRL, WMC_BYPLMIXVOLw(mix_l),
|
||||||
vol_l -= HW_VOL_DIG_THRESHOLD;
|
WMC_BYPLMIXVOL);
|
||||||
}
|
wmc_write_masked(WMC_LEFT_ADC_BOOST_CTRL,
|
||||||
else
|
WMC_L2_2BOOSTVOLw(boost_l), WMC_L2_2BOOSTVOL);
|
||||||
{
|
|
||||||
if (vol_l < HW_VOL_MIN)
|
|
||||||
vol_l = HW_VOL_MIN;
|
|
||||||
|
|
||||||
dac_l = 2*vol_l + HW_VOL_DIG_MIN;
|
|
||||||
vol_l = HW_VOL_ANA_MIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vol_r >= HW_VOL_DIG_THRESHOLD)
|
|
||||||
{
|
|
||||||
if (vol_r > HW_VOL_MAX)
|
|
||||||
vol_r = HW_VOL_MAX;
|
|
||||||
|
|
||||||
dac_r = HW_VOL_DIG_MAX;
|
|
||||||
vol_r -= HW_VOL_DIG_THRESHOLD;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (vol_r < HW_VOL_MIN)
|
|
||||||
vol_r = HW_VOL_MIN;
|
|
||||||
|
|
||||||
dac_r = 2*vol_r + HW_VOL_DIG_MIN;
|
|
||||||
vol_r = HW_VOL_ANA_MIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Have to write both channels always to have the latching work */
|
|
||||||
wmc_write_masked(WMC_LEFT_DAC_DIGITAL_VOL, dac_l, WMC_DVOL);
|
wmc_write_masked(WMC_LEFT_DAC_DIGITAL_VOL, dac_l, WMC_DVOL);
|
||||||
wmc_write_masked(WMC_LOUT1_HP_VOLUME_CTRL, vol_l, WMC_AVOL);
|
wmc_write_masked(WMC_LOUT1_HP_VOLUME_CTRL, hp_l, WMC_AVOL);
|
||||||
wmc_write_masked(WMC_RIGHT_DAC_DIGITAL_VOL, dac_r, WMC_DVOL);
|
|
||||||
wmc_write_masked(WMC_ROUT1_HP_VOLUME_CTRL, vol_r, WMC_AVOL);
|
|
||||||
|
|
||||||
if (wmc_vol.vol_l > HW_VOL_MUTE)
|
wmc_write_masked(WMC_RIGHT_MIXER_CTRL, WMC_BYPRMIXVOLw(mix_r),
|
||||||
|
WMC_BYPRMIXVOL);
|
||||||
|
wmc_write_masked(WMC_RIGHT_ADC_BOOST_CTRL,
|
||||||
|
WMC_R2_2BOOSTVOLw(boost_r), WMC_R2_2BOOSTVOL);
|
||||||
|
wmc_write_masked(WMC_RIGHT_DAC_DIGITAL_VOL, dac_r, WMC_DVOL);
|
||||||
|
wmc_write_masked(WMC_ROUT1_HP_VOLUME_CTRL, hp_r, WMC_AVOL);
|
||||||
|
|
||||||
|
if (vol_l > 0)
|
||||||
{
|
{
|
||||||
/* Not muted and going up from mute level? */
|
/* Not muted and going up from mute level? */
|
||||||
if (prev_l <= HW_VOL_MUTE && !wmc_vol.ahw_mute)
|
if (prev_l <= 0 && !wmc_vol.ahw_mute)
|
||||||
wmc_clear(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
wmc_clear(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Going to mute level? */
|
/* Going to mute level? */
|
||||||
if (prev_l > HW_VOL_MUTE)
|
if (prev_l > 0)
|
||||||
wmc_set(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
wmc_set(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wmc_vol.vol_r > HW_VOL_MUTE)
|
if (vol_r > 0)
|
||||||
{
|
{
|
||||||
/* Not muted and going up from mute level? */
|
/* Not muted and going up from mute level? */
|
||||||
if (prev_r <= HW_VOL_MIN && !wmc_vol.ahw_mute)
|
if (prev_r <= 0 && !wmc_vol.ahw_mute)
|
||||||
wmc_clear(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
wmc_clear(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Going to mute level? */
|
/* Going to mute level? */
|
||||||
if (prev_r > HW_VOL_MUTE)
|
if (prev_r > 0)
|
||||||
wmc_set(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
wmc_set(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,10 +377,10 @@ void audiohw_mute(bool mute)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Unmute outputs not at mute level */
|
/* Unmute outputs not at mute level */
|
||||||
if (wmc_vol.vol_l > HW_VOL_MUTE)
|
if (wmc_vol.vol_l > 0)
|
||||||
wmc_clear(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
wmc_clear(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
||||||
|
|
||||||
if (wmc_vol.vol_r > HW_VOL_MUTE)
|
if (wmc_vol.vol_r > 0)
|
||||||
wmc_clear(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
wmc_clear(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -491,9 +510,72 @@ void audiohw_set_frequency(int fsel)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_RECORDING
|
#ifdef HAVE_RECORDING
|
||||||
/* TODO */
|
void audiohw_set_recsrc(int source, bool recording)
|
||||||
|
{
|
||||||
|
switch (source)
|
||||||
|
{
|
||||||
|
case AUDIO_SRC_PLAYBACK:
|
||||||
|
/* Disable all audio paths but DAC */
|
||||||
|
/* Disable ADCs */
|
||||||
|
wmc_clear(WMC_ADC_CONTROL, WMC_HPFEN);
|
||||||
|
wmc_clear(WMC_POWER_MANAGEMENT2, WMC_ADCENL | WMC_ADCENR);
|
||||||
|
/* Disable bypass */
|
||||||
|
wmc_clear(WMC_LEFT_MIXER_CTRL, WMC_BYPL2LMIX);
|
||||||
|
wmc_clear(WMC_RIGHT_MIXER_CTRL, WMC_BYPR2RMIX);
|
||||||
|
/* Disable IP BOOSTMIX and PGA */
|
||||||
|
wmc_clear(WMC_POWER_MANAGEMENT2, WMC_INPPGAENL | WMC_INPPGAENR |
|
||||||
|
WMC_BOOSTENL | WMC_BOOSTENR);
|
||||||
|
wmc_clear(WMC_INPUT_CTRL, WMC_L2_2INPPGA | WMC_R2_2INPPGA);
|
||||||
|
wmc_clear(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL);
|
||||||
|
wmc_clear(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUDIO_SRC_FMRADIO:
|
||||||
|
if (recording)
|
||||||
|
{
|
||||||
|
/* Disable bypass */
|
||||||
|
wmc_clear(WMC_LEFT_MIXER_CTRL, WMC_BYPL2LMIX);
|
||||||
|
wmc_clear(WMC_RIGHT_MIXER_CTRL, WMC_BYPR2RMIX);
|
||||||
|
/* Enable ADCs, IP BOOSTMIX and PGA, route L/R2 through PGA */
|
||||||
|
wmc_set(WMC_POWER_MANAGEMENT2, WMC_ADCENL | WMC_ADCENR |
|
||||||
|
WMC_BOOSTENL | WMC_BOOSTENR | WMC_INPPGAENL |
|
||||||
|
WMC_INPPGAENR);
|
||||||
|
wmc_set(WMC_ADC_CONTROL, WMC_ADCOSR | WMC_HPFEN);
|
||||||
|
/* PGA at 0dB with +20dB boost */
|
||||||
|
wmc_write_masked(WMC_LEFT_INP_PGA_GAIN_CTRL, 0x10, WMC_AVOL);
|
||||||
|
wmc_write_masked(WMC_RIGHT_INP_PGA_GAIN_CTRL, 0x10, WMC_AVOL);
|
||||||
|
wmc_set(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL);
|
||||||
|
wmc_set(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR);
|
||||||
|
/* Connect L/R2 inputs to PGA */
|
||||||
|
wmc_set(WMC_INPUT_CTRL, WMC_L2_2INPPGA | WMC_R2_2INPPGA);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Disable PGA and ADC, enable IP BOOSTMIX, route L/R2 directly to
|
||||||
|
* IP BOOSTMIX */
|
||||||
|
wmc_clear(WMC_ADC_CONTROL, WMC_HPFEN);
|
||||||
|
wmc_write_masked(WMC_POWER_MANAGEMENT2, WMC_BOOSTENL | WMC_BOOSTENR,
|
||||||
|
WMC_BOOSTENL | WMC_BOOSTENR | WMC_INPPGAENL |
|
||||||
|
WMC_INPPGAENR | WMC_ADCENL | WMC_ADCENR);
|
||||||
|
wmc_clear(WMC_INPUT_CTRL, WMC_L2_2INPPGA | WMC_R2_2INPPGA);
|
||||||
|
wmc_clear(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL);
|
||||||
|
wmc_clear(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR);
|
||||||
|
/* Enable bypass to L/R mixers */
|
||||||
|
wmc_set(WMC_LEFT_MIXER_CTRL, WMC_BYPL2LMIX);
|
||||||
|
wmc_set(WMC_RIGHT_MIXER_CTRL, WMC_BYPR2RMIX);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void audiohw_set_recvol(int left, int right, int type)
|
void audiohw_set_recvol(int left, int right, int type)
|
||||||
{
|
{
|
||||||
(void)left; (void)right; (void)type;
|
switch (type)
|
||||||
|
{
|
||||||
|
case AUDIO_GAIN_LINEIN:
|
||||||
|
wmc_write_masked(WMC_LEFT_ADC_DIGITAL_VOL, left + 239, WMC_DVOL);
|
||||||
|
wmc_write_masked(WMC_RIGHT_ADC_DIGITAL_VOL, right + 239, WMC_DVOL);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
#endif /* HAVE_RECORDING */
|
||||||
|
|
|
@ -47,7 +47,6 @@ extern int si4700_st(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SEEK_THRESHOLD 0x16
|
#define SEEK_THRESHOLD 0x16
|
||||||
#define TUNER_VOLUME 0xC
|
|
||||||
|
|
||||||
#define I2C_ADR 0x20
|
#define I2C_ADR 0x20
|
||||||
|
|
||||||
|
@ -332,10 +331,9 @@ static void si4700_sleep(int snooze)
|
||||||
SYSCONFIG1_GPIO1 | SYSCONFIG1_GPIO2 |
|
SYSCONFIG1_GPIO1 | SYSCONFIG1_GPIO2 |
|
||||||
SYSCONFIG1_GPIO3);
|
SYSCONFIG1_GPIO3);
|
||||||
#endif
|
#endif
|
||||||
/* -6dB volume, seek threshold 12 */
|
|
||||||
si4700_write_masked(SYSCONFIG2,
|
si4700_write_masked(SYSCONFIG2,
|
||||||
SYSCONFIG2_SKEETHw(SEEK_THRESHOLD) |
|
SYSCONFIG2_SKEETHw(SEEK_THRESHOLD) |
|
||||||
SYSCONFIG2_VOLUMEw(TUNER_VOLUME),
|
SYSCONFIG2_VOLUMEw(0xF),
|
||||||
SYSCONFIG2_VOLUME | SYSCONFIG2_SEEKTH);
|
SYSCONFIG2_VOLUME | SYSCONFIG2_SEEKTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,12 +79,25 @@
|
||||||
/* Define this if you have the WM8978 audio codec */
|
/* Define this if you have the WM8978 audio codec */
|
||||||
#define HAVE_WM8978
|
#define HAVE_WM8978
|
||||||
|
|
||||||
|
/* Define bitmask of input sources - recordable bitmask can be defined
|
||||||
|
explicitly if different */
|
||||||
#define INPUT_SRC_CAPS SRC_CAP_FMRADIO
|
#define INPUT_SRC_CAPS SRC_CAP_FMRADIO
|
||||||
|
|
||||||
|
/* define the bitmask of hardware sample rates */
|
||||||
#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
|
#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
|
||||||
SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
|
SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
|
||||||
SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
|
SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
|
||||||
|
|
||||||
|
/* define the bitmask of recording sample rates */
|
||||||
|
#define REC_SAMPR_CAPS HW_SAMPR_CAPS /* Same as playback */
|
||||||
|
|
||||||
|
/* define default recording levels */
|
||||||
|
#define DEFAULT_REC_LEFT_GAIN 0
|
||||||
|
#define DEFAULT_REC_RIGHT_GAIN 0
|
||||||
|
|
||||||
|
/* Define this if you have recording capability */
|
||||||
|
#define HAVE_RECORDING
|
||||||
|
|
||||||
/* Define this if your LCD can be put to sleep. */
|
/* Define this if your LCD can be put to sleep. */
|
||||||
#define HAVE_LCD_SLEEP
|
#define HAVE_LCD_SLEEP
|
||||||
/* We don't use a setting but a fixed delay after the backlight has
|
/* We don't use a setting but a fixed delay after the backlight has
|
||||||
|
|
|
@ -777,7 +777,7 @@
|
||||||
#define AUDMUX_PTCR_TCSEL_PORT6 (0x5 << 22)
|
#define AUDMUX_PTCR_TCSEL_PORT6 (0x5 << 22)
|
||||||
#define AUDMUX_PTCR_TCSEL_PORT7 (0x6 << 22)
|
#define AUDMUX_PTCR_TCSEL_PORT7 (0x6 << 22)
|
||||||
|
|
||||||
#define AUDMUX_PTCR_RFSDIR (1 << 21)
|
#define AUDMUX_PTCR_RFS_DIR (1 << 21)
|
||||||
|
|
||||||
#define AUDMUX_PTCR_RFSSEL (0xf << 17)
|
#define AUDMUX_PTCR_RFSSEL (0xf << 17)
|
||||||
#define AUDMUX_PTCR_RFSSEL_TXFS (0x0 << 17)
|
#define AUDMUX_PTCR_RFSSEL_TXFS (0x0 << 17)
|
||||||
|
@ -922,7 +922,7 @@
|
||||||
#define SSI_SIER_TLS (0x1 << 5)
|
#define SSI_SIER_TLS (0x1 << 5)
|
||||||
#define SSI_SIER_RLS (0x1 << 4)
|
#define SSI_SIER_RLS (0x1 << 4)
|
||||||
#define SSI_SIER_RFF1 (0x1 << 3)
|
#define SSI_SIER_RFF1 (0x1 << 3)
|
||||||
#define SSI_SIER_RFF2 (0x1 << 2)
|
#define SSI_SIER_RFF0 (0x1 << 2)
|
||||||
#define SSI_SIER_TFE1 (0x1 << 1)
|
#define SSI_SIER_TFE1 (0x1 << 1)
|
||||||
#define SSI_SIER_TFE0 (0x1 << 0)
|
#define SSI_SIER_TFE0 (0x1 << 0)
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
int tenthdb2master(int db);
|
int tenthdb2master(int db);
|
||||||
void audiohw_set_headphone_vol(int vol_l, int vol_r);
|
void audiohw_set_headphone_vol(int vol_l, int vol_r);
|
||||||
void audiohw_set_frequency(int fsel);
|
void audiohw_set_frequency(int fsel);
|
||||||
|
void audiohw_set_recsrc(int source, bool recording);
|
||||||
|
|
||||||
void wmc_set(unsigned int reg, unsigned int bits);
|
void wmc_set(unsigned int reg, unsigned int bits);
|
||||||
void wmc_clear(unsigned int reg, unsigned int bits);
|
void wmc_clear(unsigned int reg, unsigned int bits);
|
||||||
|
@ -108,8 +109,8 @@ void wmc_clear(unsigned int reg, unsigned int bits);
|
||||||
|
|
||||||
/* Volums masks and macros for analogue volumes */
|
/* Volums masks and macros for analogue volumes */
|
||||||
#define WMC_AVOL 0x3f
|
#define WMC_AVOL 0x3f
|
||||||
#define WMC_AVOLr(x) ((x) & WMC_AVOLUME_MASK)
|
#define WMC_AVOLr(x) ((x) & WMC_AVOL)
|
||||||
#define WMC_AVOLw(x) ((x) & WMC_AVOLUME_MASK)
|
#define WMC_AVOLw(x) ((x) & WMC_AVOL)
|
||||||
|
|
||||||
/* WMC_SOFTWARE_RESET (0x00) */
|
/* WMC_SOFTWARE_RESET (0x00) */
|
||||||
#define WMC_RESET
|
#define WMC_RESET
|
||||||
|
@ -457,8 +458,8 @@ void wmc_clear(unsigned int reg, unsigned int bits);
|
||||||
#define WMC_PGABOOSTL (1 << 8)
|
#define WMC_PGABOOSTL (1 << 8)
|
||||||
/* 000=disabled, 001=-12dB, 010=-9dB...111=+6dB */
|
/* 000=disabled, 001=-12dB, 010=-9dB...111=+6dB */
|
||||||
#define WMC_L2_2BOOSTVOL (7 << 4)
|
#define WMC_L2_2BOOSTVOL (7 << 4)
|
||||||
#define WMC_L2_2BOOSTVOLr(x) ((x) & WMC_L2_2_BOOSTVOL) >> 4)
|
#define WMC_L2_2BOOSTVOLr(x) (((x) & WMC_L2_2BOOSTVOL) >> 4)
|
||||||
#define WMC_L2_2BOOSTVOLw(x) ((x) << 4) & WMC_L2_2_BOOSTVOL)
|
#define WMC_L2_2BOOSTVOLw(x) (((x) << 4) & WMC_L2_2BOOSTVOL)
|
||||||
/* 000=disabled, 001=-12dB, 010=-9dB...111=+6dB */
|
/* 000=disabled, 001=-12dB, 010=-9dB...111=+6dB */
|
||||||
#define WMC_AUXL2BOOSTVOL (7 << 0)
|
#define WMC_AUXL2BOOSTVOL (7 << 0)
|
||||||
#define WMC_AUXL2BOOSTVOLr(x) ((x) & WMC_AUXL2BOOSTVOL)
|
#define WMC_AUXL2BOOSTVOLr(x) ((x) & WMC_AUXL2BOOSTVOL)
|
||||||
|
@ -467,9 +468,9 @@ void wmc_clear(unsigned int reg, unsigned int bits);
|
||||||
/* WMC_RIGHT_ADC_BOOST_CTRL (0x30) */
|
/* WMC_RIGHT_ADC_BOOST_CTRL (0x30) */
|
||||||
#define WMC_PGABOOSTR (1 << 8)
|
#define WMC_PGABOOSTR (1 << 8)
|
||||||
/* 000=disabled, 001=-12dB, 010=-9dB...111=+6dB */
|
/* 000=disabled, 001=-12dB, 010=-9dB...111=+6dB */
|
||||||
#define WMC_R2_2_BOOSTVOL (7 << 4)
|
#define WMC_R2_2BOOSTVOL (7 << 4)
|
||||||
#define WMC_R2_2BOOSTVOLr(x) ((x) & WMC_R2_2_BOOSTVOL) >> 4)
|
#define WMC_R2_2BOOSTVOLr(x) (((x) & WMC_R2_2BOOSTVOL) >> 4)
|
||||||
#define WMC_R2_2BOOSTVOLw(x) ((x) << 4) & WMC_R2_2_BOOSTVOL)
|
#define WMC_R2_2BOOSTVOLw(x) (((x) << 4) & WMC_R2_2BOOSTVOL)
|
||||||
/* 000=disabled, 001=-12dB, 010=-9dB...111=+6dB */
|
/* 000=disabled, 001=-12dB, 010=-9dB...111=+6dB */
|
||||||
#define WMC_AUXR2BOOSTVOL (7 << 0)
|
#define WMC_AUXR2BOOSTVOL (7 << 0)
|
||||||
#define WMC_AUXR2BOOSTVOLr(x) ((x) & WMC_AUXR2BOOSTVOL)
|
#define WMC_AUXR2BOOSTVOLr(x) ((x) & WMC_AUXR2BOOSTVOL)
|
||||||
|
@ -487,26 +488,26 @@ void wmc_clear(unsigned int reg, unsigned int bits);
|
||||||
/* WMC_LEFT_MIXER_CTRL (0x32) */
|
/* WMC_LEFT_MIXER_CTRL (0x32) */
|
||||||
/* 000=-15dB, 001=-12dB...101=0dB, 110=+3dB, 111=+6dB */
|
/* 000=-15dB, 001=-12dB...101=0dB, 110=+3dB, 111=+6dB */
|
||||||
#define WMC_AUXLMIXVOL (7 << 6)
|
#define WMC_AUXLMIXVOL (7 << 6)
|
||||||
#define WMC_AUXLMIXVOLr(x) ((x) & WMC_AUXLMIXVOL) >> 6)
|
#define WMC_AUXLMIXVOLr(x) (((x) & WMC_AUXLMIXVOL) >> 6)
|
||||||
#define WMC_AUXLMIXVOLw(x) ((x) << 6) & WMC_AUXLMIXVOL)
|
#define WMC_AUXLMIXVOLw(x) (((x) << 6) & WMC_AUXLMIXVOL)
|
||||||
#define WMC_AUXL2LMIX (1 << 5)
|
#define WMC_AUXL2LMIX (1 << 5)
|
||||||
/* 000=-15dB, 001=-12dB...101=0dB, 110=+3dB, 111=+6dB */
|
/* 000=-15dB, 001=-12dB...101=0dB, 110=+3dB, 111=+6dB */
|
||||||
#define WMC_BYPLMIXVOL (7 << 2)
|
#define WMC_BYPLMIXVOL (7 << 2)
|
||||||
#define WMC_BYPLMIXVOLr(x) ((x) & WMC_BYPLMIXVOL) >> 2)
|
#define WMC_BYPLMIXVOLr(x) (((x) & WMC_BYPLMIXVOL) >> 2)
|
||||||
#define WMC_BYPLMIXVOLw(x) ((x) << 2) & WMC_BYPLMIXVOL)
|
#define WMC_BYPLMIXVOLw(x) (((x) << 2) & WMC_BYPLMIXVOL)
|
||||||
#define WMC_BYPL2LMIX (1 << 1)
|
#define WMC_BYPL2LMIX (1 << 1)
|
||||||
#define WMC_DACL2LMIX (1 << 0)
|
#define WMC_DACL2LMIX (1 << 0)
|
||||||
|
|
||||||
/* WMC_RIGHT_MIXER_CTRL (0x33) */
|
/* WMC_RIGHT_MIXER_CTRL (0x33) */
|
||||||
/* 000=-15dB, 001=-12dB...101=0dB, 110=+3dB, 111=+6dB */
|
/* 000=-15dB, 001=-12dB...101=0dB, 110=+3dB, 111=+6dB */
|
||||||
#define WMC_AUXRMIXVOL (7 << 6)
|
#define WMC_AUXRMIXVOL (7 << 6)
|
||||||
#define WMC_AUXRMIXVOLr(x) ((x) & WMC_AUXRMIXVOL) >> 6)
|
#define WMC_AUXRMIXVOLr(x) (((x) & WMC_AUXRMIXVOL) >> 6)
|
||||||
#define WMC_AUXRMIXVOLw(x) ((x) << 6) & WMC_AUXRMIXVOL)
|
#define WMC_AUXRMIXVOLw(x) (((x) << 6) & WMC_AUXRMIXVOL)
|
||||||
#define WMC_AUXR2RMIX (1 << 5)
|
#define WMC_AUXR2RMIX (1 << 5)
|
||||||
/* 000=-15dB, 001=-12dB...101=0dB, 110=+3dB, 111=+6dB */
|
/* 000=-15dB, 001=-12dB...101=0dB, 110=+3dB, 111=+6dB */
|
||||||
#define WMC_BYPRMIXVOL (7 << 2)
|
#define WMC_BYPRMIXVOL (7 << 2)
|
||||||
#define WMC_BYPRMIXVOLr(x) ((x) & WMC_BYPRMIXVOL) >> 2)
|
#define WMC_BYPRMIXVOLr(x) (((x) & WMC_BYPRMIXVOL) >> 2)
|
||||||
#define WMC_BYPRMIXVOLw(x) ((x) << 2) & WMC_BYPRMIXVOL)
|
#define WMC_BYPRMIXVOLw(x) (((x) << 2) & WMC_BYPRMIXVOL)
|
||||||
#define WMC_BYPR2RMIX (1 << 1)
|
#define WMC_BYPR2RMIX (1 << 1)
|
||||||
#define WMC_DACR2RMIX (1 << 0)
|
#define WMC_DACR2RMIX (1 << 0)
|
||||||
|
|
||||||
|
@ -518,14 +519,12 @@ void wmc_clear(unsigned int reg, unsigned int bits);
|
||||||
/* Uses WMC_AVOL* macros */
|
/* Uses WMC_AVOL* macros */
|
||||||
|
|
||||||
/* WMC_OUT3_MIXER_CTRL (0x38) */
|
/* WMC_OUT3_MIXER_CTRL (0x38) */
|
||||||
#define WMC_OUT3MUTE (1 << 6)
|
|
||||||
#define WMC_OUT42OUT3 (1 << 3)
|
#define WMC_OUT42OUT3 (1 << 3)
|
||||||
#define WMC_BYPL2OUT3 (1 << 2)
|
#define WMC_BYPL2OUT3 (1 << 2)
|
||||||
#define WMC_LMIX2OUT3 (1 << 1)
|
#define WMC_LMIX2OUT3 (1 << 1)
|
||||||
#define WMC_LDAC2OUT3 (1 << 0)
|
#define WMC_LDAC2OUT3 (1 << 0)
|
||||||
|
|
||||||
/* WMC_OUT4_MONO_MIXER_CTRL (0x39) */
|
/* WMC_OUT4_MONO_MIXER_CTRL (0x39) */
|
||||||
#define WMC_OUT4MUTE (1 << 6)
|
|
||||||
#define WMC_HALFSIG (1 << 5)
|
#define WMC_HALFSIG (1 << 5)
|
||||||
#define WMC_LMIX2OUT4 (1 << 4)
|
#define WMC_LMIX2OUT4 (1 << 4)
|
||||||
#define WMC_LDAC2OUT4 (1 << 3)
|
#define WMC_LDAC2OUT4 (1 << 3)
|
||||||
|
|
|
@ -629,7 +629,7 @@ void sound_set(int setting, int value)
|
||||||
#if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
|
#if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
|
||||||
&& !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
|
&& !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
|
||||||
&& !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
|
&& !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
|
||||||
&& !defined (HAVE_WM8731)) \
|
&& !defined (HAVE_WM8731) && !defined (HAVE_WM8978)) \
|
||||||
|| defined(SIMULATOR)
|
|| defined(SIMULATOR)
|
||||||
int sound_val2phys(int setting, int value)
|
int sound_val2phys(int setting, int value)
|
||||||
{
|
{
|
||||||
|
@ -707,6 +707,24 @@ int sound_val2phys(int setting, int value)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
#elif defined(HAVE_WM8978)
|
||||||
|
int result;
|
||||||
|
|
||||||
|
switch (setting)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_RECORDING
|
||||||
|
case SOUND_LEFT_GAIN:
|
||||||
|
case SOUND_RIGHT_GAIN:
|
||||||
|
case SOUND_MIC_GAIN:
|
||||||
|
result = value * 5;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = value;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
#else
|
#else
|
||||||
(void)setting;
|
(void)setting;
|
||||||
|
|
|
@ -18,39 +18,55 @@
|
||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "wm8978.h"
|
#include "config.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "audiohw.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
|
||||||
|
/* Set the audio source for IIS TX */
|
||||||
void audio_set_output_source(int source)
|
void audio_set_output_source(int source)
|
||||||
{
|
{
|
||||||
(void)source; /* TODO */
|
switch (source)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case AUDIO_SRC_PLAYBACK:
|
||||||
|
/* Receive data from PORT1 (SSI1) */
|
||||||
|
AUDMUX_PDCR4 = AUDMUX_PDCR_RXDSEL_PORT1;
|
||||||
|
/* wmc_clear(WMC_COMPANDING_CTRL, WMC_LOOPBACK); */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUDIO_SRC_FMRADIO:
|
||||||
|
/* External source - receive data from self (loopback to TX) */
|
||||||
|
AUDMUX_PDCR4 = AUDMUX_PDCR_RXDSEL_PORT4;
|
||||||
|
/* wmc_set(WMC_COMPANDING_CTRL, WMC_LOOPBACK); */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_input_mux(int source, unsigned int flags)
|
void audio_input_mux(int source, unsigned int flags)
|
||||||
{
|
{
|
||||||
(void)flags;
|
/* Prevent pops from unneeded switching */
|
||||||
|
static int last_source = AUDIO_SRC_PLAYBACK;
|
||||||
|
bool recording = flags & SRCF_RECORDING;
|
||||||
|
static bool last_recording = false;
|
||||||
|
|
||||||
switch (source)
|
switch (source)
|
||||||
{
|
{
|
||||||
case AUDIO_SRC_PLAYBACK:
|
|
||||||
/* deselect bypass patths and set volume to -15dB */
|
|
||||||
wmc_clear(WMC_LEFT_MIXER_CTRL, (WMC_BYPL2LMIX) | (7<<2));
|
|
||||||
wmc_clear(WMC_RIGHT_MIXER_CTRL, (WMC_BYPR2RMIX) | (7<<2));
|
|
||||||
/* disable L2/R2 inputs and boost stage */
|
|
||||||
wmc_clear(WMC_POWER_MANAGEMENT2,
|
|
||||||
WMC_INPPGAENR | WMC_INPPGAENL | WMC_BOOSTENL | WMC_BOOSTENR);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AUDIO_SRC_FMRADIO:
|
|
||||||
/* enable L2/R2 inputs and boost stage */
|
|
||||||
wmc_set(WMC_POWER_MANAGEMENT2,
|
|
||||||
WMC_INPPGAENR | WMC_INPPGAENL | WMC_BOOSTENL | WMC_BOOSTENR);
|
|
||||||
/* select bypass patths and set volume to 0dB */
|
|
||||||
wmc_set(WMC_LEFT_MIXER_CTRL, (WMC_BYPL2LMIX) | (5<<2));
|
|
||||||
wmc_set(WMC_RIGHT_MIXER_CTRL, (WMC_BYPR2RMIX) | (5<<2));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
source = AUDIO_SRC_PLAYBACK;
|
source = AUDIO_SRC_PLAYBACK;
|
||||||
}
|
/* Fallthrough */
|
||||||
|
case AUDIO_SRC_PLAYBACK: /* playback - no recording */
|
||||||
|
if (source != last_source)
|
||||||
|
audiohw_set_recsrc(AUDIO_SRC_PLAYBACK, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUDIO_SRC_FMRADIO: /* recording and playback */
|
||||||
|
if (source != last_source || recording != last_recording)
|
||||||
|
audiohw_set_recsrc(AUDIO_SRC_FMRADIO, recording);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_source = source;
|
||||||
|
last_recording = recording;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,17 +111,12 @@ void pcm_play_dma_init(void)
|
||||||
SSI_SCR2 &= ~SSI_SCR_SSIEN;
|
SSI_SCR2 &= ~SSI_SCR_SSIEN;
|
||||||
SSI_SCR1 &= ~SSI_SCR_SSIEN;
|
SSI_SCR1 &= ~SSI_SCR_SSIEN;
|
||||||
|
|
||||||
SSI_SIER1 = SSI_SIER_TFE0;
|
|
||||||
SSI_SIER2 = 0;
|
|
||||||
|
|
||||||
/* Set up audio mux */
|
/* Set up audio mux */
|
||||||
|
|
||||||
/* Port 1 (internally connected to SSI1)
|
/* Port 1 (internally connected to SSI1)
|
||||||
* All clocking is output sourced from port 4 */
|
* All clocking is output sourced from port 4 */
|
||||||
AUDMUX_PTCR1 = AUDMUX_PTCR_TFS_DIR | AUDMUX_PTCR_TFSEL_PORT4 |
|
AUDMUX_PTCR1 = AUDMUX_PTCR_TFS_DIR | AUDMUX_PTCR_TFSEL_PORT4 |
|
||||||
AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT4 |
|
AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT4 |
|
||||||
AUDMUX_PTCR_RFSDIR | AUDMUX_PTCR_RFSSEL_PORT4 |
|
|
||||||
AUDMUX_PTCR_RCLKDIR | AUDMUX_PTCR_RCSEL_PORT4 |
|
|
||||||
AUDMUX_PTCR_SYN;
|
AUDMUX_PTCR_SYN;
|
||||||
|
|
||||||
/* Receive data from port 4 */
|
/* Receive data from port 4 */
|
||||||
|
@ -133,18 +128,22 @@ void pcm_play_dma_init(void)
|
||||||
/* Receive data from port 1 */
|
/* Receive data from port 1 */
|
||||||
AUDMUX_PDCR4 = AUDMUX_PDCR_RXDSEL_PORT1;
|
AUDMUX_PDCR4 = AUDMUX_PDCR_RXDSEL_PORT1;
|
||||||
|
|
||||||
/* Port 2 (internally connected to SSI2) routes clocking to port 5 to
|
/* PORT2 (internally connected to SSI2) routes clocking to PORT5 to
|
||||||
* provide MCLK to the codec */
|
* provide MCLK to the codec */
|
||||||
/* All port 2 clocks are inputs taken from SSI2 */
|
/* TX clocks are inputs taken from SSI2 */
|
||||||
AUDMUX_PTCR2 = 0;
|
/* RX clocks are outputs taken from PORT4 */
|
||||||
AUDMUX_PDCR2 = 0;
|
AUDMUX_PTCR2 = AUDMUX_PTCR_RFS_DIR | AUDMUX_PTCR_RFSSEL_PORT4 |
|
||||||
/* Port 5 outputs TCLK sourced from port 2 */
|
AUDMUX_PTCR_RCLKDIR | AUDMUX_PTCR_RCSEL_PORT4;
|
||||||
|
/* RX data taken from PORT4 */
|
||||||
|
AUDMUX_PDCR2 = AUDMUX_PDCR_RXDSEL_PORT4;
|
||||||
|
|
||||||
|
/* PORT5 outputs TCLK sourced from PORT2 (SSI2) */
|
||||||
AUDMUX_PTCR5 = AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT2;
|
AUDMUX_PTCR5 = AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT2;
|
||||||
AUDMUX_PDCR5 = 0;
|
AUDMUX_PDCR5 = 0;
|
||||||
|
|
||||||
/* Setup SSIs */
|
/* Setup SSIs */
|
||||||
|
|
||||||
/* SSI1 - interface for all I2S data */
|
/* SSI1 - SoC software interface for all I2S data out */
|
||||||
SSI_SCR1 = SSI_SCR_SYN | SSI_SCR_I2S_MODE_SLAVE;
|
SSI_SCR1 = SSI_SCR_SYN | SSI_SCR_I2S_MODE_SLAVE;
|
||||||
SSI_STCR1 = SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI |
|
SSI_STCR1 = SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI |
|
||||||
SSI_STCR_TEFS | SSI_STCR_TFEN0;
|
SSI_STCR_TEFS | SSI_STCR_TFEN0;
|
||||||
|
@ -153,26 +152,11 @@ void pcm_play_dma_init(void)
|
||||||
SSI_STCCR1 = SSI_STRCCR_WL16 | SSI_STRCCR_DCw(2-1) |
|
SSI_STCCR1 = SSI_STRCCR_WL16 | SSI_STRCCR_DCw(2-1) |
|
||||||
SSI_STRCCR_PMw(4-1);
|
SSI_STRCCR_PMw(4-1);
|
||||||
|
|
||||||
|
/* Transmit low watermark - 2 samples in FIFO */
|
||||||
|
SSI_SFCSR1 = SSI_SFCSR_TFWM1w(1) | SSI_SFCSR_TFWM0w(2);
|
||||||
SSI_STMSK1 = 0;
|
SSI_STMSK1 = 0;
|
||||||
|
|
||||||
/* Receive */
|
/* SSI2 - provides MCLK to codec. Receives data from codec. */
|
||||||
SSI_SRCR1 = SSI_SRCR_RXBIT0 | SSI_SRCR_RSCKP | SSI_SRCR_RFSI |
|
|
||||||
SSI_SRCR_REFS | SSI_SRCR_RFEN0;
|
|
||||||
|
|
||||||
/* 16 bits per word, 2 words per frame */
|
|
||||||
SSI_SRCCR1 = SSI_STRCCR_WL16 | SSI_STRCCR_DCw(2-1) |
|
|
||||||
SSI_STRCCR_PMw(4-1);
|
|
||||||
|
|
||||||
/* Receive high watermark - 6 samples in FIFO
|
|
||||||
* Transmit low watermark - 2 samples in FIFO */
|
|
||||||
SSI_SFCSR1 = SSI_SFCSR_RFWM1w(8) | SSI_SFCSR_TFWM1w(1) |
|
|
||||||
SSI_SFCSR_RFWM0w(6) | SSI_SFCSR_TFWM0w(2);
|
|
||||||
|
|
||||||
SSI_SRMSK1 = 0;
|
|
||||||
|
|
||||||
/* SSI2 - provides MCLK only */
|
|
||||||
SSI_SCR2 = 0;
|
|
||||||
SSI_SRCR2 = 0;
|
|
||||||
SSI_STCR2 = SSI_STCR_TXDIR;
|
SSI_STCR2 = SSI_STCR_TXDIR;
|
||||||
|
|
||||||
/* f(INT_BIT_CLK) =
|
/* f(INT_BIT_CLK) =
|
||||||
|
@ -189,6 +173,20 @@ void pcm_play_dma_init(void)
|
||||||
*/
|
*/
|
||||||
SSI_STCCR2 = SSI_STRCCR_DIV2 | SSI_STRCCR_PMw(1-1);
|
SSI_STCCR2 = SSI_STRCCR_DIV2 | SSI_STRCCR_PMw(1-1);
|
||||||
|
|
||||||
|
/* SSI2 - receive - asynchronous clocks */
|
||||||
|
SSI_SCR2 = SSI_SCR_I2S_MODE_SLAVE;
|
||||||
|
|
||||||
|
SSI_SRCR2 = SSI_SRCR_RXBIT0 | SSI_SRCR_RSCKP | SSI_SRCR_RFSI |
|
||||||
|
SSI_SRCR_REFS;
|
||||||
|
|
||||||
|
/* 16 bits per word, 2 words per frame */
|
||||||
|
SSI_SRCCR2 = SSI_STRCCR_WL16 | SSI_STRCCR_DCw(2-1) |
|
||||||
|
SSI_STRCCR_PMw(4-1);
|
||||||
|
|
||||||
|
/* Receive high watermark - 6 samples in FIFO */
|
||||||
|
SSI_SFCSR2 = SSI_SFCSR_RFWM1w(8) | SSI_SFCSR_RFWM0w(6);
|
||||||
|
SSI_SRMSK2 = 0;
|
||||||
|
|
||||||
/* Enable SSI2 (codec clock) */
|
/* Enable SSI2 (codec clock) */
|
||||||
SSI_SCR2 |= SSI_SCR_SSIEN;
|
SSI_SCR2 |= SSI_SCR_SSIEN;
|
||||||
|
|
||||||
|
@ -211,6 +209,7 @@ static void play_start_pcm(void)
|
||||||
|
|
||||||
/* Fill the FIFO or start when data is used up */
|
/* Fill the FIFO or start when data is used up */
|
||||||
SSI_SCR1 |= SSI_SCR_SSIEN; /* Enable SSI */
|
SSI_SCR1 |= SSI_SCR_SSIEN; /* Enable SSI */
|
||||||
|
SSI_STCR1 |= SSI_STCR_TFEN0; /* Enable TX FIFO */
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
@ -235,6 +234,7 @@ static void play_stop_pcm(void)
|
||||||
while (SSI_SFCSR_TFCNT0r(SSI_SFCSR1) > 0);
|
while (SSI_SFCSR_TFCNT0r(SSI_SFCSR1) > 0);
|
||||||
|
|
||||||
/* Disable transmission */
|
/* Disable transmission */
|
||||||
|
SSI_STCR1 &= ~SSI_STCR_TFEN0;
|
||||||
SSI_SCR1 &= ~(SSI_SCR_TE | SSI_SCR_SSIEN);
|
SSI_SCR1 &= ~(SSI_SCR_TE | SSI_SCR_SSIEN);
|
||||||
|
|
||||||
/* Do not enable interrupt on unlock */
|
/* Do not enable interrupt on unlock */
|
||||||
|
@ -285,4 +285,113 @@ const void * pcm_play_dma_get_peak_buffer(int *count)
|
||||||
return (void *)((addr + 2) & ~3);
|
return (void *)((addr + 2) & ~3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Any recording functionality should be implemented similarly */
|
#ifdef HAVE_RECORDING
|
||||||
|
static struct dma_data dma_rec_data =
|
||||||
|
{
|
||||||
|
/* Initialize to a locked, stopped state */
|
||||||
|
.p = NULL,
|
||||||
|
.size = 0,
|
||||||
|
.locked = 0,
|
||||||
|
.state = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
static void __attribute__((interrupt("IRQ"))) SSI2_HANDLER(void)
|
||||||
|
{
|
||||||
|
register pcm_more_callback_type2 more_ready;
|
||||||
|
|
||||||
|
while (dma_rec_data.size > 0)
|
||||||
|
{
|
||||||
|
if (SSI_SFCSR_RFCNT0r(SSI_SFCSR2) < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*dma_rec_data.p++ = SSI_SRX0_2;
|
||||||
|
*dma_rec_data.p++ = SSI_SRX0_2;
|
||||||
|
dma_rec_data.size -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
more_ready = pcm_callback_more_ready;
|
||||||
|
|
||||||
|
if (more_ready == NULL || more_ready(0) < 0) {
|
||||||
|
/* Finished recording */
|
||||||
|
pcm_rec_dma_stop();
|
||||||
|
pcm_rec_dma_stopped_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcm_rec_lock(void)
|
||||||
|
{
|
||||||
|
if (++dma_rec_data.locked == 1)
|
||||||
|
{
|
||||||
|
/* Atomically disable receive interrupt */
|
||||||
|
imx31_regclr32(&SSI_SIER2, SSI_SIER_RIE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcm_rec_unlock(void)
|
||||||
|
{
|
||||||
|
if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0)
|
||||||
|
{
|
||||||
|
/* Atomically enable receive interrupt */
|
||||||
|
imx31_regset32(&SSI_SIER2, SSI_SIER_RIE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcm_record_more(void *start, size_t size)
|
||||||
|
{
|
||||||
|
pcm_rec_peak_addr = start; /* Start peaking at dest */
|
||||||
|
dma_rec_data.p = start; /* Start of RX buffer */
|
||||||
|
dma_rec_data.size = size; /* Bytes to transfer */
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcm_rec_dma_stop(void)
|
||||||
|
{
|
||||||
|
/* Stop receiving data */
|
||||||
|
SSI_SCR2 &= ~SSI_SCR_RE; /* Disable RX */
|
||||||
|
SSI_SRCR2 &= ~SSI_SRCR_RFEN0; /* Disable RX FIFO */
|
||||||
|
|
||||||
|
dma_rec_data.state = 0;
|
||||||
|
|
||||||
|
avic_disable_int(SSI2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcm_rec_dma_start(void *addr, size_t size)
|
||||||
|
{
|
||||||
|
pcm_rec_dma_stop();
|
||||||
|
|
||||||
|
pcm_rec_peak_addr = addr;
|
||||||
|
dma_rec_data.p = addr;
|
||||||
|
dma_rec_data.size = size;
|
||||||
|
|
||||||
|
dma_rec_data.state = 1;
|
||||||
|
|
||||||
|
avic_enable_int(SSI2, IRQ, 9, SSI2_HANDLER);
|
||||||
|
|
||||||
|
SSI_SRCR2 |= SSI_SRCR_RFEN0; /* Enable RX FIFO */
|
||||||
|
|
||||||
|
/* Ensure clear FIFO */
|
||||||
|
while (SSI_SFCSR2 & SSI_SFCSR_RFCNT0)
|
||||||
|
SSI_SRX0_2;
|
||||||
|
|
||||||
|
/* Enable receive */
|
||||||
|
SSI_SCR2 |= SSI_SCR_RE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcm_rec_dma_close(void)
|
||||||
|
{
|
||||||
|
pcm_rec_dma_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcm_rec_dma_init(void)
|
||||||
|
{
|
||||||
|
pcm_rec_dma_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const void * pcm_rec_dma_get_peak_buffer(int *count)
|
||||||
|
{
|
||||||
|
unsigned long addr = (uint32_t)pcm_rec_peak_addr;
|
||||||
|
unsigned long end = (uint32_t)dma_rec_data.p;
|
||||||
|
*count = (end >> 2) - (addr >> 2);
|
||||||
|
return (void *)(addr & ~3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_RECORDING */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue