e200v1/c200v1: Implement limited samplerate switching. Rates 24kHz and below are...
authorjethead71 <jethead71@a1c6a512-1295-4272-9138-f99709370657>
Sat, 26 Jun 2010 10:07:17 +0000 (26 10:07 +0000)
committerjethead71 <jethead71@a1c6a512-1295-4272-9138-f99709370657>
Sat, 26 Jun 2010 10:07:17 +0000 (26 10:07 +0000)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27139 a1c6a512-1295-4272-9138-f99709370657

12 files changed:
apps/plugins/pitch_detector.c
apps/recorder/pcm_record.c
firmware/drivers/audio/as3514.c
firmware/drivers/audio/sdl.c
firmware/export/as3514.h
firmware/export/config/sansac200.h
firmware/export/config/sansae200.h
firmware/export/pcm.h
firmware/export/pcm_sampr.h
firmware/pcm.c
firmware/target/arm/i2s-pp.c
firmware/target/arm/sandisk/audio-c200_e200.c

index 208b146..36248a5 100644 (file)
@@ -1106,7 +1106,7 @@ void record_and_get_pitch(void)
         }
     }
     rb->pcm_close_recording();
-    rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
+    rb->pcm_set_frequency(REC_SAMPR_DEFAULT | SAMPR_TYPE_REC);
 #ifdef HAVE_SCHEDULER_BOOSTCTRL
     rb->cancel_cpu_boost();
 #endif
@@ -1141,7 +1141,7 @@ void init_everything(void)
     sample_rate = rb->round_value_to_list32(9000, rb->rec_freq_sampr,
                                             REC_NUM_FREQ, false);
     sample_rate = rb->rec_freq_sampr[sample_rate];
-    rb->pcm_set_frequency(sample_rate);
+    rb->pcm_set_frequency(sample_rate | SAMPR_TYPE_REC);
     rb->pcm_init_recording();
     
     /* GUI */
index 687a706..3217509 100644 (file)
@@ -288,8 +288,8 @@ static void pcm_rec_have_more(int status, void **start, size_t *size)
 
 static void reset_hardware(void)
 {
-    /* reset pcm to defaults (playback only) */
-    pcm_set_frequency(HW_SAMPR_DEFAULT);
+    /* reset pcm to defaults */
+    pcm_set_frequency(REC_SAMPR_DEFAULT | SAMPR_TYPE_REC);
     audio_set_output_source(AUDIO_SRC_PLAYBACK);
     pcm_apply_settings();
 }
@@ -1216,7 +1216,7 @@ static void pcmrec_set_recording_options(
         /* round to HW playback rates for monitoring */
         index = round_value_to_list32(sr, hw_freq_sampr,
                                       HW_NUM_FREQ, false);
-        pcm_set_frequency(hw_freq_sampr[index]);
+        pcm_set_frequency(hw_freq_sampr[index] | SAMPR_TYPE_REC);
         /* encoders with a limited number of rates do their own rounding */
     }
     else
@@ -1224,7 +1224,7 @@ static void pcmrec_set_recording_options(
     {
         /* set sample rate from frequency selection */
         sample_rate = rec_freq_sampr[rec_frequency];
-        pcm_set_frequency(sample_rate);
+        pcm_set_frequency(sample_rate | SAMPR_TYPE_REC);
     }
 
     /* set monitoring */
index 34dc9ad..957aba8 100644 (file)
@@ -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;
 }
 
index c063192..f4c622d 100644 (file)
@@ -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)
 {
index ffcf918..de975ce 100644 (file)
@@ -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 */
 
index 5905b6a..6c05ba5 100644 (file)
@@ -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
 
index 8f4f323..501e9ea 100644 (file)
@@ -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)
index 02fa04c..e388e29 100644 (file)
@@ -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);
index 2204b9c..54db8a1 100644 (file)
@@ -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 */
index 8080823..72fe23c 100644 (file)
@@ -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 */
index c9d66d5..83f3951 100644 (file)
 #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;
index 1d78e71..0037bac 100644 (file)
@@ -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 */
+}