[ALSA] hdsp - Add support for fine tuning of sample rate support to HDSP 9632
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>
This commit is contained in:
Родитель
02a5039fc7
Коммит
e4b6088c8c
|
@ -275,6 +275,11 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
|
||||||
#define HDSP_Frequency128KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency0)
|
#define HDSP_Frequency128KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency0)
|
||||||
#define HDSP_Frequency176_4KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1)
|
#define HDSP_Frequency176_4KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1)
|
||||||
#define HDSP_Frequency192KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0)
|
#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_encode_latency(x) (((x)<<1) & HDSP_LatencyMask)
|
||||||
#define hdsp_decode_latency(x) (((x) & HDSP_LatencyMask)>>1)
|
#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)
|
else if (rate >= 56000)
|
||||||
rate /= 2;
|
rate /= 2;
|
||||||
|
|
||||||
/* RME says n = 104857600000000, but in the windows MADI driver, I see:
|
n = DDS_NUMERATOR;
|
||||||
// return 104857600000000 / rate; // 100 MHz
|
|
||||||
return 110100480000000 / rate; // 105 MHz
|
|
||||||
*/
|
|
||||||
n = 104857600000000ULL; /* = 2^20 * 10^8 */
|
|
||||||
div64_32(&n, rate, &r);
|
div64_32(&n, rate, &r);
|
||||||
/* n should be less than 2^32 for being written to FREQ register */
|
/* n should be less than 2^32 for being written to FREQ register */
|
||||||
snd_assert((n >> 32) == 0);
|
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;
|
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[] = {
|
static struct snd_kcontrol_new snd_hdsp_9632_controls[] = {
|
||||||
HDSP_DA_GAIN("DA Gain", 0),
|
HDSP_DA_GAIN("DA Gain", 0),
|
||||||
HDSP_AD_GAIN("AD Gain", 0),
|
HDSP_AD_GAIN("AD Gain", 0),
|
||||||
HDSP_PHONE_GAIN("Phones 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[] = {
|
static struct snd_kcontrol_new snd_hdsp_controls[] = {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче