Commit 973dca93 authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Takashi Iwai

sound: virtuoso: add PCM1796 oversampling control

Add a control to increase the oversampling factor to 128x on cards with
PCM1796 or PCM1792A DACs.
Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 76ffe1e3
...@@ -173,8 +173,11 @@ struct xonar_pcm179x { ...@@ -173,8 +173,11 @@ struct xonar_pcm179x {
struct xonar_generic generic; struct xonar_generic generic;
unsigned int dacs; unsigned int dacs;
u8 pcm1796_regs[4][5]; u8 pcm1796_regs[4][5];
unsigned int current_rate;
bool os_128;
bool hp_active; bool hp_active;
s8 hp_gain_offset; s8 hp_gain_offset;
bool has_cs2000;
u8 cs2000_fun_cfg_1; u8 cs2000_fun_cfg_1;
}; };
...@@ -277,6 +280,7 @@ static void pcm1796_init(struct oxygen *chip) ...@@ -277,6 +280,7 @@ static void pcm1796_init(struct oxygen *chip)
PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64;
pcm1796_registers_init(chip); pcm1796_registers_init(chip);
data->current_rate = 48000;
} }
static void xonar_d2_init(struct oxygen *chip) static void xonar_d2_init(struct oxygen *chip)
...@@ -401,6 +405,7 @@ static void xonar_st_init(struct oxygen *chip) ...@@ -401,6 +405,7 @@ static void xonar_st_init(struct oxygen *chip)
{ {
struct xonar_pcm179x *data = chip->model_data; struct xonar_pcm179x *data = chip->model_data;
data->has_cs2000 = 1;
data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
...@@ -486,18 +491,57 @@ static void xonar_st_resume(struct oxygen *chip) ...@@ -486,18 +491,57 @@ static void xonar_st_resume(struct oxygen *chip)
xonar_stx_resume(chip); xonar_stx_resume(chip);
} }
static void set_pcm1796_params(struct oxygen *chip, static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate)
struct snd_pcm_hw_params *params) {
struct xonar_pcm179x *data = chip->model_data;
if (rate <= 32000)
return OXYGEN_I2S_MCLK_512;
else if (rate <= 48000 && data->os_128)
return OXYGEN_I2S_MCLK_512;
else if (rate <= 96000)
return OXYGEN_I2S_MCLK_256;
else
return OXYGEN_I2S_MCLK_128;
}
static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip,
unsigned int channel,
struct snd_pcm_hw_params *params)
{
if (channel == PCM_MULTICH)
return mclk_from_rate(chip, params_rate(params));
else
return oxygen_default_i2s_mclk(chip, channel, params);
}
static void update_pcm1796_oversampling(struct oxygen *chip)
{ {
struct xonar_pcm179x *data = chip->model_data; struct xonar_pcm179x *data = chip->model_data;
unsigned int i; unsigned int i;
u8 reg; u8 reg;
reg = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; if (data->current_rate <= 32000)
reg = PCM1796_OS_128;
else if (data->current_rate <= 48000 && data->os_128)
reg = PCM1796_OS_128;
else if (data->current_rate <= 96000 || data->os_128)
reg = PCM1796_OS_64;
else
reg = PCM1796_OS_32;
for (i = 0; i < data->dacs; ++i) for (i = 0; i < data->dacs; ++i)
pcm1796_write_cached(chip, i, 20, reg); pcm1796_write_cached(chip, i, 20, reg);
} }
static void set_pcm1796_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
struct xonar_pcm179x *data = chip->model_data;
data->current_rate = params_rate(params);
update_pcm1796_oversampling(chip);
}
static void update_pcm1796_volume(struct oxygen *chip) static void update_pcm1796_volume(struct oxygen *chip)
{ {
struct xonar_pcm179x *data = chip->model_data; struct xonar_pcm179x *data = chip->model_data;
...@@ -526,26 +570,44 @@ static void update_pcm1796_mute(struct oxygen *chip) ...@@ -526,26 +570,44 @@ static void update_pcm1796_mute(struct oxygen *chip)
pcm1796_write_cached(chip, i, 18, value); pcm1796_write_cached(chip, i, 18, value);
} }
static void set_cs2000_params(struct oxygen *chip, static void update_cs2000_rate(struct oxygen *chip, unsigned int rate)
struct snd_pcm_hw_params *params)
{ {
/* XXX Why is the I2S A MCLK half the actual I2S multich MCLK? */ struct xonar_pcm179x *data = chip->model_data;
static const u8 rate_mclks[] = {
[OXYGEN_RATE_32000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_128,
[OXYGEN_RATE_44100] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128,
[OXYGEN_RATE_48000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128,
[OXYGEN_RATE_64000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256,
[OXYGEN_RATE_88200] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256,
[OXYGEN_RATE_96000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256,
[OXYGEN_RATE_176400] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256,
[OXYGEN_RATE_192000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256,
};
unsigned int rate_index;
u8 rate_mclk, reg; u8 rate_mclk, reg;
rate_index = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) switch (rate) {
& OXYGEN_I2S_RATE_MASK; /* XXX Why is the I2S A MCLK half the actual I2S MCLK? */
rate_mclk = rate_mclks[rate_index]; case 32000:
rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
break;
case 44100:
if (data->os_128)
rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
else
rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128;
break;
default: /* 48000 */
if (data->os_128)
rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
else
rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128;
break;
case 64000:
rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
break;
case 88200:
rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
break;
case 96000:
rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
break;
case 176400:
rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
break;
case 192000:
rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
break;
}
oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,
OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);
if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128) if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128)
...@@ -558,7 +620,7 @@ static void set_cs2000_params(struct oxygen *chip, ...@@ -558,7 +620,7 @@ static void set_cs2000_params(struct oxygen *chip,
static void set_st_params(struct oxygen *chip, static void set_st_params(struct oxygen *chip,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
set_cs2000_params(chip, params); update_cs2000_rate(chip, params_rate(params));
set_pcm1796_params(chip, params); set_pcm1796_params(chip, params);
} }
...@@ -580,6 +642,59 @@ static const struct snd_kcontrol_new alt_switch = { ...@@ -580,6 +642,59 @@ static const struct snd_kcontrol_new alt_switch = {
.private_value = GPIO_D2_ALT, .private_value = GPIO_D2_ALT,
}; };
static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
{
static const char *const names[2] = { "64x", "128x" };
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
info->count = 1;
info->value.enumerated.items = 2;
if (info->value.enumerated.item >= 2)
info->value.enumerated.item = 1;
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
return 0;
}
static int os_128_get(struct snd_kcontrol *ctl,
struct snd_ctl_elem_value *value)
{
struct oxygen *chip = ctl->private_data;
struct xonar_pcm179x *data = chip->model_data;
value->value.enumerated.item[0] = data->os_128;
return 0;
}
static int os_128_put(struct snd_kcontrol *ctl,
struct snd_ctl_elem_value *value)
{
struct oxygen *chip = ctl->private_data;
struct xonar_pcm179x *data = chip->model_data;
int changed;
mutex_lock(&chip->mutex);
changed = value->value.enumerated.item[0] != data->os_128;
if (changed) {
data->os_128 = value->value.enumerated.item[0];
if (data->has_cs2000)
update_cs2000_rate(chip, data->current_rate);
oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
mclk_from_rate(chip, data->current_rate),
OXYGEN_I2S_MCLK_MASK);
update_pcm1796_oversampling(chip);
}
mutex_unlock(&chip->mutex);
return changed;
}
static const struct snd_kcontrol_new os_128_control = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "DAC Oversampling Playback Enum",
.info = os_128_info,
.get = os_128_get,
.put = os_128_put,
};
static int st_output_switch_info(struct snd_kcontrol *ctl, static int st_output_switch_info(struct snd_kcontrol *ctl,
struct snd_ctl_elem_info *info) struct snd_ctl_elem_info *info)
{ {
...@@ -745,7 +860,20 @@ static int xonar_st_control_filter(struct snd_kcontrol_new *template) ...@@ -745,7 +860,20 @@ static int xonar_st_control_filter(struct snd_kcontrol_new *template)
static int xonar_d2_mixer_init(struct oxygen *chip) static int xonar_d2_mixer_init(struct oxygen *chip)
{ {
return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); int err;
err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
if (err < 0)
return err;
err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip));
if (err < 0)
return err;
return 0;
}
static int xonar_hdav_mixer_init(struct oxygen *chip)
{
return snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip));
} }
static int xonar_st_mixer_init(struct oxygen *chip) static int xonar_st_mixer_init(struct oxygen *chip)
...@@ -759,6 +887,9 @@ static int xonar_st_mixer_init(struct oxygen *chip) ...@@ -759,6 +887,9 @@ static int xonar_st_mixer_init(struct oxygen *chip)
if (err < 0) if (err < 0)
return err; return err;
} }
err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip));
if (err < 0)
return err;
return 0; return 0;
} }
...@@ -771,7 +902,7 @@ static const struct oxygen_model model_xonar_d2 = { ...@@ -771,7 +902,7 @@ static const struct oxygen_model model_xonar_d2 = {
.cleanup = xonar_d2_cleanup, .cleanup = xonar_d2_cleanup,
.suspend = xonar_d2_suspend, .suspend = xonar_d2_suspend,
.resume = xonar_d2_resume, .resume = xonar_d2_resume,
.get_i2s_mclk = oxygen_default_i2s_mclk, .get_i2s_mclk = get_pcm1796_i2s_mclk,
.set_dac_params = set_pcm1796_params, .set_dac_params = set_pcm1796_params,
.set_adc_params = xonar_set_cs53x1_params, .set_adc_params = xonar_set_cs53x1_params,
.update_dac_volume = update_pcm1796_volume, .update_dac_volume = update_pcm1796_volume,
...@@ -798,11 +929,12 @@ static const struct oxygen_model model_xonar_hdav = { ...@@ -798,11 +929,12 @@ static const struct oxygen_model model_xonar_hdav = {
.longname = "Asus Virtuoso 200", .longname = "Asus Virtuoso 200",
.chip = "AV200", .chip = "AV200",
.init = xonar_hdav_init, .init = xonar_hdav_init,
.mixer_init = xonar_hdav_mixer_init,
.cleanup = xonar_hdav_cleanup, .cleanup = xonar_hdav_cleanup,
.suspend = xonar_hdav_suspend, .suspend = xonar_hdav_suspend,
.resume = xonar_hdav_resume, .resume = xonar_hdav_resume,
.pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter,
.get_i2s_mclk = oxygen_default_i2s_mclk, .get_i2s_mclk = get_pcm1796_i2s_mclk,
.set_dac_params = set_hdav_params, .set_dac_params = set_hdav_params,
.set_adc_params = xonar_set_cs53x1_params, .set_adc_params = xonar_set_cs53x1_params,
.update_dac_volume = update_pcm1796_volume, .update_dac_volume = update_pcm1796_volume,
...@@ -833,7 +965,7 @@ static const struct oxygen_model model_xonar_st = { ...@@ -833,7 +965,7 @@ static const struct oxygen_model model_xonar_st = {
.cleanup = xonar_st_cleanup, .cleanup = xonar_st_cleanup,
.suspend = xonar_st_suspend, .suspend = xonar_st_suspend,
.resume = xonar_st_resume, .resume = xonar_st_resume,
.get_i2s_mclk = oxygen_default_i2s_mclk, .get_i2s_mclk = get_pcm1796_i2s_mclk,
.set_dac_params = set_st_params, .set_dac_params = set_st_params,
.set_adc_params = xonar_set_cs53x1_params, .set_adc_params = xonar_set_cs53x1_params,
.update_dac_volume = update_pcm1796_volume, .update_dac_volume = update_pcm1796_volume,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment