summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/audio/as3514.c9
-rw-r--r--firmware/drivers/audio/sdl.c4
-rw-r--r--firmware/export/as3514.h1
-rw-r--r--firmware/export/config/sansac200.h4
-rw-r--r--firmware/export/config/sansae200.h9
-rw-r--r--firmware/export/pcm.h13
-rw-r--r--firmware/export/pcm_sampr.h20
-rw-r--r--firmware/pcm.c20
-rw-r--r--firmware/target/arm/i2s-pp.c6
-rw-r--r--firmware/target/arm/sandisk/audio-c200_e200.c83
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)
327 327
328void audiohw_set_frequency(int fsel) 328void audiohw_set_frequency(int fsel)
329{ 329{
330#if defined(SANSA_E200) || defined(SANSA_C200)
331 if ((unsigned)fsel >= HW_NUM_FREQ)
332 fsel = HW_FREQ_DEFAULT;
333
334 as3514_write(AS3514_PLLMODE, hw_freq_sampr[fsel] < 24000 ?
335 PLLMODE_LRCK_8_23 : PLLMODE_LRCK_24_48);
336
337 audiohw_set_sampr_dividers(fsel);
338#endif
330 (void)fsel; 339 (void)fsel;
331} 340}
332 341
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)
162void audiohw_set_depth_3d(int value) 162void audiohw_set_depth_3d(int value)
163 { (void)value; } 163 { (void)value; }
164#endif 164#endif
165#if defined(HAVE_SAMPR_TYPE_REC)
166unsigned int pcm_sampr_type_rec_to_play(int samplerate)
167 { return samplerate; }
168#endif
165#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) 169#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
166int mas_codec_readreg(int reg) 170int mas_codec_readreg(int reg)
167{ 171{
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);
28 28
29extern void audiohw_set_master_vol(int vol_l, int vol_r); 29extern void audiohw_set_master_vol(int vol_l, int vol_r);
30extern void audiohw_set_lineout_vol(int vol_l, int vol_r); 30extern void audiohw_set_lineout_vol(int vol_l, int vol_r);
31extern void audiohw_set_sampr_dividers(int fsel);
31 32
32/* Register Descriptions */ 33/* Register Descriptions */
33 34
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 @@
7#define MODEL_NUMBER 20 7#define MODEL_NUMBER 20
8#define MODEL_NAME "Sandisk Sansa c200 series" 8#define MODEL_NAME "Sandisk Sansa c200 series"
9 9
10#define HW_SAMPR_CAPS (SAMPR_CAP_44) 10#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32)
11 11
12/* define this if you have recording possibility */ 12/* define this if you have recording possibility */
13#define HAVE_RECORDING 13#define HAVE_RECORDING
14 14
15#define REC_SAMPR_CAPS (SAMPR_CAP_22) 15#define REC_SAMPR_CAPS (SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16)
16#define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */ 16#define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */
17#define REC_SAMPR_DEFAULT SAMPR_22 17#define REC_SAMPR_DEFAULT SAMPR_22
18 18
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 @@
7#define MODEL_NUMBER 16 7#define MODEL_NUMBER 16
8#define MODEL_NAME "Sandisk Sansa e200 series" 8#define MODEL_NAME "Sandisk Sansa e200 series"
9 9
10#define HW_SAMPR_CAPS (SAMPR_CAP_44) 10#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32)
11 11
12/* define this if you have recording possibility */ 12/* define this if you have recording possibility */
13#define HAVE_RECORDING 13#define HAVE_RECORDING
14 14
15#define REC_SAMPR_CAPS (SAMPR_CAP_22) 15#define REC_SAMPR_CAPS (SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16)
16#define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */ 16#define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */
17#define REC_SAMPR_DEFAULT SAMPR_22 17#define REC_SAMPR_DEFAULT SAMPR_22
18 18
19/* because the samplerates don't match at each point, we must be able to
20 * tell PCM which set of rates to use. not needed if recording rates are
21 * a simple subset of playback rates and are equal values. */
22#define CONFIG_SAMPR_TYPES
23
19/* Define bitmask of input sources - recordable bitmask can be defined 24/* Define bitmask of input sources - recordable bitmask can be defined
20 explicitly if different */ 25 explicitly if different */
21#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) 26#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,
54 size_t *size); 54 size_t *size);
55typedef void (*pcm_rec_callback_type)(int status, void **start, size_t *size); 55typedef void (*pcm_rec_callback_type)(int status, void **start, size_t *size);
56 56
57/* set the pcm frequency - use values in hw_sampr_list 57/* set the pcm frequency - use values in hw_sampr_list
58 * use -1 for the default frequency 58 * when CONFIG_SAMPR_TYPES is #defined, or-in SAMPR_TYPE_* fields with
59 */ 59 * frequency value. SAMPR_TYPE_PLAY is 0 and the default if none is
60 * specified. */
61#ifdef CONFIG_SAMPR_TYPES
62#ifdef SAMPR_TYPE_REC
63unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate);
64#endif
65#endif /* CONFIG_SAMPR_TYPES */
66
60void pcm_set_frequency(unsigned int samplerate); 67void pcm_set_frequency(unsigned int samplerate);
61/* apply settings to hardware immediately */ 68/* apply settings to hardware immediately */
62void pcm_apply_settings(void); 69void 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
312extern const unsigned long rec_freq_sampr[REC_NUM_FREQ]; 312extern const unsigned long rec_freq_sampr[REC_NUM_FREQ];
313#endif /* HAVE_RECORDING */ 313#endif /* HAVE_RECORDING */
314 314
315#ifdef CONFIG_SAMPR_TYPES
316
317#define SAMPR_TYPE_MASK (0xff << 24)
318#define SAMPR_TYPE_PLAY (0x00 << 24)
319#ifdef HAVE_RECORDING
320#define SAMPR_TYPE_REC (0x01 << 24)
321#endif
322
323unsigned int sampr_type_rec_to_play(unsigned int samplerate);
324
325#else /* ndef CONFIG_SAMPR_TYPES */
326
327/* Types are ignored and == 0 */
328#define SAMPR_TYPE_PLAY 0
329#ifdef HAVE_RECORDING
330#define SAMPR_TYPE_REC 0
331#endif
332
333#endif /* CONFIG_SAMPR_TYPES */
334
315#endif /* PCM_SAMPR_H */ 335#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)
361{ 361{
362 logf("pcm_set_frequency"); 362 logf("pcm_set_frequency");
363 363
364 int index = round_value_to_list32(samplerate, hw_freq_sampr, 364 int index;
365 HW_NUM_FREQ, false); 365
366#ifdef CONFIG_SAMPR_TYPES
367 unsigned int type = samplerate & SAMPR_TYPE_MASK;
368 samplerate &= ~SAMPR_TYPE_MASK;
369
370#ifdef SAMPR_TYPE_REC
371 /* For now, supported targets have direct conversion when configured with
372 * CONFIG_SAMPR_TYPES.
373 * Some hypothetical target with independent rates would need slightly
374 * different handling throughout this source. */
375 if (type == SAMPR_TYPE_REC)
376 samplerate = pcm_sampr_type_rec_to_play(samplerate);
377#endif
378#endif /* CONFIG_SAMPR_TYPES */
379
380 index = round_value_to_list32(samplerate, hw_freq_sampr,
381 HW_NUM_FREQ, false);
366 382
367 if (samplerate != hw_freq_sampr[index]) 383 if (samplerate != hw_freq_sampr[index])
368 index = HW_FREQ_DEFAULT; /* Invalid = default */ 384 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 @@
28#include "system.h" 28#include "system.h"
29#include "cpu.h" 29#include "cpu.h"
30#include "i2s.h" 30#include "i2s.h"
31#if defined (SANSA_E200) || defined (SANSA_C200)
32#include "audiohw.h"
33#include "pcm_sampr.h"
34#endif
31 35
32#if CONFIG_CPU == PP5002 36#if CONFIG_CPU == PP5002
33void i2s_reset(void) 37void i2s_reset(void)
@@ -70,6 +74,8 @@ void i2s_reset(void)
70 IISCLK = (IISCLK & ~0x1ff) | 31; 74 IISCLK = (IISCLK & ~0x1ff) | 31;
71 IISDIV = (IISDIV & ~0xc0000000) | (2 << 30); 75 IISDIV = (IISDIV & ~0xc0000000) | (2 << 30);
72 IISDIV = (IISDIV & ~0x3f) | 16; 76 IISDIV = (IISDIV & ~0x3f) | 16;
77#elif defined (SANSA_E200) || defined (SANSA_C200)
78 audiohw_set_sampr_dividers(HW_FREQ_DEFAULT);
73#else 79#else
74 IISCLK = (IISCLK & ~0x1ff) | 33; 80 IISCLK = (IISCLK & ~0x1ff) | 33;
75 IISDIV = 7; 81 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 @@
22#include "cpu.h" 22#include "cpu.h"
23#include "audio.h" 23#include "audio.h"
24#include "sound.h" 24#include "sound.h"
25#include "general.h"
25 26
26int audio_channels = 2; 27int audio_channels = 2;
27int audio_output_source = AUDIO_SRC_PLAYBACK; 28int audio_output_source = AUDIO_SRC_PLAYBACK;
@@ -92,3 +93,85 @@ void audio_input_mux(int source, unsigned flags)
92 93
93 last_source = source; 94 last_source = source;
94} /* audio_input_mux */ 95} /* audio_input_mux */
96
97
98void audiohw_set_sampr_dividers(int fsel)
99{
100 /* Seems to predivide 24MHz by 2 for a source clock of 12MHz. Maybe
101 * there's a way to set that? */
102 static const struct
103 {
104 unsigned char iisclk;
105 unsigned char iisdiv;
106 } regvals[HW_NUM_FREQ] =
107 {
108 /* 8kHz - 24kHz work well but there seems to be a minor crackling
109 * issue for playback at times and all possibilities were checked
110 * for the divisors without any positive change.
111 * 32kHz - 48kHz seem fine all around. */
112#if 0
113 [HW_FREQ_8] = /* CLK / 1500 (8000Hz) */
114 {
115 .iisclk = 24,
116 .iisdiv = 59,
117 },
118 [HW_FREQ_11] = /* CLK / 1088 (~11029.41Hz) */
119 {
120 .iisclk = 33,
121 .iisdiv = 31,
122 },
123 [HW_FREQ_12] = /* CLK / 1000 (120000Hz) */
124 {
125 .iisclk = 49,
126 .iisdiv = 19,
127 },
128 [HW_FREQ_16] = /* CLK / 750 (16000Hz) */
129 {
130 .iisclk = 24,
131 .iisdiv = 29,
132 },
133 [HW_FREQ_22] = /* CLK / 544 (~22058.82Hz) */
134 {
135 .iisclk = 33,
136 .iisdiv = 15,
137 },
138 [HW_FREQ_24] = /* CLK / 500 (24000Hz) */
139 {
140 .iisclk = 49,
141 .iisdiv = 9,
142 },
143#endif
144 [HW_FREQ_32] = /* CLK / 375 (32000Hz) */
145 {
146 .iisclk = 24,
147 .iisdiv = 14,
148 },
149 [HW_FREQ_44] = /* CLK / 272 (~44117.68Hz) */
150 {
151 .iisclk = 33,
152 .iisdiv = 7,
153 },
154 [HW_FREQ_48] = /* CLK / 250 (48000Hz) */
155 {
156 .iisclk = 49,
157 .iisdiv = 4,
158 },
159 /* going a bit higher would be nice to get 64kHz play, 32kHz rec, but a
160 * close enough division isn't obtainable unless CLK can be changed */
161 };
162
163 IISCLK = (IISCLK & ~0x17ff) | regvals[fsel].iisclk;
164 IISDIV = (IISDIV & ~0xc000003f) | regvals[fsel].iisdiv;
165}
166
167unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate)
168{
169 /* Check if the samplerate is in the list of recordable rates.
170 * Fail to default if not */
171 int index = round_value_to_list32(samplerate, rec_freq_sampr,
172 REC_NUM_FREQ, false);
173 if (samplerate != rec_freq_sampr[index])
174 return HW_SAMPR_DEFAULT;
175
176 return samplerate * 2; /* Recording rates are 1/2 the codec clock */
177}