diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/audio/as3514.c | 9 | ||||
-rw-r--r-- | firmware/drivers/audio/sdl.c | 4 | ||||
-rw-r--r-- | firmware/export/as3514.h | 1 | ||||
-rw-r--r-- | firmware/export/config/sansac200.h | 4 | ||||
-rw-r--r-- | firmware/export/config/sansae200.h | 9 | ||||
-rw-r--r-- | firmware/export/pcm.h | 13 | ||||
-rw-r--r-- | firmware/export/pcm_sampr.h | 20 | ||||
-rw-r--r-- | firmware/pcm.c | 20 | ||||
-rw-r--r-- | firmware/target/arm/i2s-pp.c | 6 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/audio-c200_e200.c | 83 |
10 files changed, 160 insertions, 9 deletions
diff --git a/firmware/drivers/audio/as3514.c b/firmware/drivers/audio/as3514.c index 34dc9ad29f..957aba8dbb 100644 --- a/firmware/drivers/audio/as3514.c +++ b/firmware/drivers/audio/as3514.c @@ -327,6 +327,15 @@ void audiohw_close(void) void audiohw_set_frequency(int fsel) { +#if defined(SANSA_E200) || defined(SANSA_C200) + if ((unsigned)fsel >= HW_NUM_FREQ) + fsel = HW_FREQ_DEFAULT; + + as3514_write(AS3514_PLLMODE, hw_freq_sampr[fsel] < 24000 ? + PLLMODE_LRCK_8_23 : PLLMODE_LRCK_24_48); + + audiohw_set_sampr_dividers(fsel); +#endif (void)fsel; } diff --git a/firmware/drivers/audio/sdl.c b/firmware/drivers/audio/sdl.c index c063192873..f4c622d7a6 100644 --- a/firmware/drivers/audio/sdl.c +++ b/firmware/drivers/audio/sdl.c @@ -162,6 +162,10 @@ void audiohw_set_eq_band_width(unsigned int band, int value) void audiohw_set_depth_3d(int value) { (void)value; } #endif +#if defined(HAVE_SAMPR_TYPE_REC) +unsigned int pcm_sampr_type_rec_to_play(int samplerate) + { return samplerate; } +#endif #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) int mas_codec_readreg(int reg) { diff --git a/firmware/export/as3514.h b/firmware/export/as3514.h index ffcf9186e7..de975ce3c6 100644 --- a/firmware/export/as3514.h +++ b/firmware/export/as3514.h @@ -28,6 +28,7 @@ extern int tenthdb2master(int db); extern void audiohw_set_master_vol(int vol_l, int vol_r); extern void audiohw_set_lineout_vol(int vol_l, int vol_r); +extern void audiohw_set_sampr_dividers(int fsel); /* Register Descriptions */ diff --git a/firmware/export/config/sansac200.h b/firmware/export/config/sansac200.h index 5905b6a3f9..6c05ba5a1c 100644 --- a/firmware/export/config/sansac200.h +++ b/firmware/export/config/sansac200.h @@ -7,12 +7,12 @@ #define MODEL_NUMBER 20 #define MODEL_NAME "Sandisk Sansa c200 series" -#define HW_SAMPR_CAPS (SAMPR_CAP_44) +#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32) /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS (SAMPR_CAP_22) +#define REC_SAMPR_CAPS (SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16) #define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */ #define REC_SAMPR_DEFAULT SAMPR_22 diff --git a/firmware/export/config/sansae200.h b/firmware/export/config/sansae200.h index 8f4f3235dc..501e9eac37 100644 --- a/firmware/export/config/sansae200.h +++ b/firmware/export/config/sansae200.h @@ -7,15 +7,20 @@ #define MODEL_NUMBER 16 #define MODEL_NAME "Sandisk Sansa e200 series" -#define HW_SAMPR_CAPS (SAMPR_CAP_44) +#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32) /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS (SAMPR_CAP_22) +#define REC_SAMPR_CAPS (SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16) #define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */ #define REC_SAMPR_DEFAULT SAMPR_22 +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES + /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) diff --git a/firmware/export/pcm.h b/firmware/export/pcm.h index 02fa04cb7e..e388e29f0c 100644 --- a/firmware/export/pcm.h +++ b/firmware/export/pcm.h @@ -54,9 +54,16 @@ typedef void (*pcm_play_callback_type)(unsigned char **start, size_t *size); typedef void (*pcm_rec_callback_type)(int status, void **start, size_t *size); -/* set the pcm frequency - use values in hw_sampr_list - * use -1 for the default frequency - */ +/* set the pcm frequency - use values in hw_sampr_list + * when CONFIG_SAMPR_TYPES is #defined, or-in SAMPR_TYPE_* fields with + * frequency value. SAMPR_TYPE_PLAY is 0 and the default if none is + * specified. */ +#ifdef CONFIG_SAMPR_TYPES +#ifdef SAMPR_TYPE_REC +unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate); +#endif +#endif /* CONFIG_SAMPR_TYPES */ + void pcm_set_frequency(unsigned int samplerate); /* apply settings to hardware immediately */ void pcm_apply_settings(void); diff --git a/firmware/export/pcm_sampr.h b/firmware/export/pcm_sampr.h index 2204b9c059..54db8a1dfb 100644 --- a/firmware/export/pcm_sampr.h +++ b/firmware/export/pcm_sampr.h @@ -312,4 +312,24 @@ enum rec_freq_indexes extern const unsigned long rec_freq_sampr[REC_NUM_FREQ]; #endif /* HAVE_RECORDING */ +#ifdef CONFIG_SAMPR_TYPES + +#define SAMPR_TYPE_MASK (0xff << 24) +#define SAMPR_TYPE_PLAY (0x00 << 24) +#ifdef HAVE_RECORDING +#define SAMPR_TYPE_REC (0x01 << 24) +#endif + +unsigned int sampr_type_rec_to_play(unsigned int samplerate); + +#else /* ndef CONFIG_SAMPR_TYPES */ + +/* Types are ignored and == 0 */ +#define SAMPR_TYPE_PLAY 0 +#ifdef HAVE_RECORDING +#define SAMPR_TYPE_REC 0 +#endif + +#endif /* CONFIG_SAMPR_TYPES */ + #endif /* PCM_SAMPR_H */ diff --git a/firmware/pcm.c b/firmware/pcm.c index 8080823077..72fe23cb16 100644 --- a/firmware/pcm.c +++ b/firmware/pcm.c @@ -361,8 +361,24 @@ void pcm_set_frequency(unsigned int samplerate) { logf("pcm_set_frequency"); - int index = round_value_to_list32(samplerate, hw_freq_sampr, - HW_NUM_FREQ, false); + int index; + +#ifdef CONFIG_SAMPR_TYPES + unsigned int type = samplerate & SAMPR_TYPE_MASK; + samplerate &= ~SAMPR_TYPE_MASK; + +#ifdef SAMPR_TYPE_REC + /* For now, supported targets have direct conversion when configured with + * CONFIG_SAMPR_TYPES. + * Some hypothetical target with independent rates would need slightly + * different handling throughout this source. */ + if (type == SAMPR_TYPE_REC) + samplerate = pcm_sampr_type_rec_to_play(samplerate); +#endif +#endif /* CONFIG_SAMPR_TYPES */ + + index = round_value_to_list32(samplerate, hw_freq_sampr, + HW_NUM_FREQ, false); if (samplerate != hw_freq_sampr[index]) index = HW_FREQ_DEFAULT; /* Invalid = default */ diff --git a/firmware/target/arm/i2s-pp.c b/firmware/target/arm/i2s-pp.c index c9d66d53ae..83f39515c4 100644 --- a/firmware/target/arm/i2s-pp.c +++ b/firmware/target/arm/i2s-pp.c @@ -28,6 +28,10 @@ #include "system.h" #include "cpu.h" #include "i2s.h" +#if defined (SANSA_E200) || defined (SANSA_C200) +#include "audiohw.h" +#include "pcm_sampr.h" +#endif #if CONFIG_CPU == PP5002 void i2s_reset(void) @@ -70,6 +74,8 @@ void i2s_reset(void) IISCLK = (IISCLK & ~0x1ff) | 31; IISDIV = (IISDIV & ~0xc0000000) | (2 << 30); IISDIV = (IISDIV & ~0x3f) | 16; +#elif defined (SANSA_E200) || defined (SANSA_C200) + audiohw_set_sampr_dividers(HW_FREQ_DEFAULT); #else IISCLK = (IISCLK & ~0x1ff) | 33; IISDIV = 7; diff --git a/firmware/target/arm/sandisk/audio-c200_e200.c b/firmware/target/arm/sandisk/audio-c200_e200.c index 1d78e71541..0037bac58b 100644 --- a/firmware/target/arm/sandisk/audio-c200_e200.c +++ b/firmware/target/arm/sandisk/audio-c200_e200.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "audio.h" #include "sound.h" +#include "general.h" int audio_channels = 2; int audio_output_source = AUDIO_SRC_PLAYBACK; @@ -92,3 +93,85 @@ void audio_input_mux(int source, unsigned flags) last_source = source; } /* audio_input_mux */ + + +void audiohw_set_sampr_dividers(int fsel) +{ + /* Seems to predivide 24MHz by 2 for a source clock of 12MHz. Maybe + * there's a way to set that? */ + static const struct + { + unsigned char iisclk; + unsigned char iisdiv; + } regvals[HW_NUM_FREQ] = + { + /* 8kHz - 24kHz work well but there seems to be a minor crackling + * issue for playback at times and all possibilities were checked + * for the divisors without any positive change. + * 32kHz - 48kHz seem fine all around. */ +#if 0 + [HW_FREQ_8] = /* CLK / 1500 (8000Hz) */ + { + .iisclk = 24, + .iisdiv = 59, + }, + [HW_FREQ_11] = /* CLK / 1088 (~11029.41Hz) */ + { + .iisclk = 33, + .iisdiv = 31, + }, + [HW_FREQ_12] = /* CLK / 1000 (120000Hz) */ + { + .iisclk = 49, + .iisdiv = 19, + }, + [HW_FREQ_16] = /* CLK / 750 (16000Hz) */ + { + .iisclk = 24, + .iisdiv = 29, + }, + [HW_FREQ_22] = /* CLK / 544 (~22058.82Hz) */ + { + .iisclk = 33, + .iisdiv = 15, + }, + [HW_FREQ_24] = /* CLK / 500 (24000Hz) */ + { + .iisclk = 49, + .iisdiv = 9, + }, +#endif + [HW_FREQ_32] = /* CLK / 375 (32000Hz) */ + { + .iisclk = 24, + .iisdiv = 14, + }, + [HW_FREQ_44] = /* CLK / 272 (~44117.68Hz) */ + { + .iisclk = 33, + .iisdiv = 7, + }, + [HW_FREQ_48] = /* CLK / 250 (48000Hz) */ + { + .iisclk = 49, + .iisdiv = 4, + }, + /* going a bit higher would be nice to get 64kHz play, 32kHz rec, but a + * close enough division isn't obtainable unless CLK can be changed */ + }; + + IISCLK = (IISCLK & ~0x17ff) | regvals[fsel].iisclk; + IISDIV = (IISDIV & ~0xc000003f) | regvals[fsel].iisdiv; +} + +unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate) +{ + /* Check if the samplerate is in the list of recordable rates. + * Fail to default if not */ + int index = round_value_to_list32(samplerate, rec_freq_sampr, + REC_NUM_FREQ, false); + if (samplerate != rec_freq_sampr[index]) + return HW_SAMPR_DEFAULT; + + return samplerate * 2; /* Recording rates are 1/2 the codec clock */ +} |