[ALSA] hdsp - Add support for fine tuning of sample rate support to HDSP 9632
authorJulian Cable <julian_cable@yahoo.com>
Mon, 19 Mar 2007 10:44:40 +0000 (11:44 +0100)
committerJaroslav Kysela <perex@suse.cz>
Fri, 11 May 2007 14:55:50 +0000 (16:55 +0200)
Add 'DDS Sample Rate Offset' control. Allows values in Hz from -5000 to +5000.
The value is added to the nominal sample rate and written to the DDS register.

Signed-off-by: Julian Cable <julian_cable@yahoo.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
sound/pci/rme9652/hdsp.c

index 6540037a11e4d9c2e693acc801baf39f6ef1758c..4b20f848dba29356f5aada8ffc5336071759bc8a 100644 (file)
@@ -275,6 +275,11 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
 #define HDSP_Frequency128KHz   (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency0)
 #define HDSP_Frequency176_4KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1)
 #define HDSP_Frequency192KHz   (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0)
+/* RME says n = 104857600000000, but in the windows MADI driver, I see:
+       return 104857600000000 / rate; // 100 MHz
+       return 110100480000000 / rate; // 105 MHz
+*/
+#define DDS_NUMERATOR 104857600000000ULL;  /*  =  2^20 * 10^8 */
 
 #define hdsp_encode_latency(x)       (((x)<<1) & HDSP_LatencyMask)
 #define hdsp_decode_latency(x)       (((x) & HDSP_LatencyMask)>>1)
@@ -1001,11 +1006,7 @@ static void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
        else if (rate >= 56000)
                rate /= 2;
 
-       /* RME says n = 104857600000000, but in the windows MADI driver, I see:
-//     return 104857600000000 / rate; // 100 MHz
-       return 110100480000000 / rate; // 105 MHz
-        */        
-       n = 104857600000000ULL;  /*  =  2^20 * 10^8 */
+       n = DDS_NUMERATOR;
        div64_32(&n, rate, &r);
        /* n should be less than 2^32 for being written to FREQ register */
        snd_assert((n >> 32) == 0);
@@ -3085,11 +3086,83 @@ static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct sn
        return 0;
 }
 
+#define HDSP_DDS_OFFSET(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_hdsp_info_dds_offset, \
+  .get = snd_hdsp_get_dds_offset, \
+  .put = snd_hdsp_put_dds_offset \
+}
+
+static int hdsp_dds_offset(struct hdsp *hdsp)
+{
+       u64 n;
+       u32 r;
+       unsigned int dds_value = hdsp->dds_value;
+       int system_sample_rate = hdsp->system_sample_rate;
+
+       n = DDS_NUMERATOR;
+       /*
+        * dds_value = n / rate
+        * rate = n / dds_value
+        */
+       div64_32(&n, dds_value, &r);
+       if (system_sample_rate >= 112000)
+               n *= 4;
+       else if (system_sample_rate >= 56000)
+               n *= 2;
+       return ((int)n) - system_sample_rate;
+}
+
+static int hdsp_set_dds_offset(struct hdsp *hdsp, int offset_hz)
+{
+       int rate = hdsp->system_sample_rate + offset_hz;
+       hdsp_set_dds_value(hdsp, rate);
+       return 0;
+}
+
+static int snd_hdsp_info_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = -5000;
+       uinfo->value.integer.max = 5000;
+       return 0;
+}
+
+static int snd_hdsp_get_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.enumerated.item[0] = hdsp_dds_offset(hdsp);
+       return 0;
+}
+
+static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+       int change;
+       int val;
+       
+       if (!snd_hdsp_use_is_exclusive(hdsp))
+               return -EBUSY;
+       val = ucontrol->value.enumerated.item[0];
+       spin_lock_irq(&hdsp->lock);
+       if (val != hdsp_dds_offset(hdsp))
+               change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0;
+       else
+               change = 0;
+       spin_unlock_irq(&hdsp->lock);
+       return change;
+}
+
 static struct snd_kcontrol_new snd_hdsp_9632_controls[] = {
 HDSP_DA_GAIN("DA Gain", 0),
 HDSP_AD_GAIN("AD Gain", 0),
 HDSP_PHONE_GAIN("Phones Gain", 0),
-HDSP_XLR_BREAKOUT_CABLE("XLR Breakout Cable", 0)
+HDSP_XLR_BREAKOUT_CABLE("XLR Breakout Cable", 0),
+HDSP_DDS_OFFSET("DDS Sample Rate Offset", 0)
 };
 
 static struct snd_kcontrol_new snd_hdsp_controls[] = {