diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2009-09-28 05:21:21 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-09-28 05:55:00 -0400 |
commit | 4852ad02476ab2bbc874f6f8fda9e677e0f09c87 (patch) | |
tree | 0edcea50bffb7a643e3a72e29bcc920dd7ab71dc /sound/pci | |
parent | 973dca93a3d46cca7e4743300f8a510b779906af (diff) |
sound: oxygen: add digital filter control
Add a control to select between sharp and slow roll-of filter responses
of the DACs.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/oxygen/oxygen.c | 65 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_cs43xx.c | 82 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_pcm179x.c | 85 |
3 files changed, 223 insertions, 9 deletions
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index d12fd9efe94e..3ad9eb00aebd 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -352,6 +352,70 @@ static void set_ak5385_params(struct oxygen *chip, | |||
352 | value, GPIO_AK5385_DFS_MASK); | 352 | value, GPIO_AK5385_DFS_MASK); |
353 | } | 353 | } |
354 | 354 | ||
355 | static int rolloff_info(struct snd_kcontrol *ctl, | ||
356 | struct snd_ctl_elem_info *info) | ||
357 | { | ||
358 | static const char *const names[2] = { | ||
359 | "Sharp Roll-off", "Slow Roll-off" | ||
360 | }; | ||
361 | |||
362 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
363 | info->count = 1; | ||
364 | info->value.enumerated.items = 2; | ||
365 | if (info->value.enumerated.item >= 2) | ||
366 | info->value.enumerated.item = 1; | ||
367 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int rolloff_get(struct snd_kcontrol *ctl, | ||
372 | struct snd_ctl_elem_value *value) | ||
373 | { | ||
374 | struct oxygen *chip = ctl->private_data; | ||
375 | struct generic_data *data = chip->model_data; | ||
376 | |||
377 | value->value.enumerated.item[0] = | ||
378 | (data->ak4396_regs[0][AK4396_CONTROL_2] & AK4396_SLOW) != 0; | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int rolloff_put(struct snd_kcontrol *ctl, | ||
383 | struct snd_ctl_elem_value *value) | ||
384 | { | ||
385 | struct oxygen *chip = ctl->private_data; | ||
386 | struct generic_data *data = chip->model_data; | ||
387 | unsigned int i; | ||
388 | int changed; | ||
389 | u8 reg; | ||
390 | |||
391 | mutex_lock(&chip->mutex); | ||
392 | reg = data->ak4396_regs[0][AK4396_CONTROL_2]; | ||
393 | if (value->value.enumerated.item[0]) | ||
394 | reg |= AK4396_SLOW; | ||
395 | else | ||
396 | reg &= ~AK4396_SLOW; | ||
397 | changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2]; | ||
398 | if (changed) { | ||
399 | for (i = 0; i < 4; ++i) | ||
400 | ak4396_write(chip, i, AK4396_CONTROL_2, reg); | ||
401 | } | ||
402 | mutex_unlock(&chip->mutex); | ||
403 | return changed; | ||
404 | } | ||
405 | |||
406 | static const struct snd_kcontrol_new rolloff_control = { | ||
407 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
408 | .name = "DAC Filter Playback Enum", | ||
409 | .info = rolloff_info, | ||
410 | .get = rolloff_get, | ||
411 | .put = rolloff_put, | ||
412 | }; | ||
413 | |||
414 | static int generic_mixer_init(struct oxygen *chip) | ||
415 | { | ||
416 | return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | ||
417 | } | ||
418 | |||
355 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | 419 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); |
356 | 420 | ||
357 | static const struct oxygen_model model_generic = { | 421 | static const struct oxygen_model model_generic = { |
@@ -359,6 +423,7 @@ static const struct oxygen_model model_generic = { | |||
359 | .longname = "C-Media Oxygen HD Audio", | 423 | .longname = "C-Media Oxygen HD Audio", |
360 | .chip = "CMI8788", | 424 | .chip = "CMI8788", |
361 | .init = generic_init, | 425 | .init = generic_init, |
426 | .mixer_init = generic_mixer_init, | ||
362 | .cleanup = generic_cleanup, | 427 | .cleanup = generic_cleanup, |
363 | .resume = generic_resume, | 428 | .resume = generic_resume, |
364 | .get_i2s_mclk = oxygen_default_i2s_mclk, | 429 | .get_i2s_mclk = oxygen_default_i2s_mclk, |
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index a83f827feb34..16c226bfcd2b 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c | |||
@@ -69,7 +69,7 @@ | |||
69 | 69 | ||
70 | struct xonar_cs43xx { | 70 | struct xonar_cs43xx { |
71 | struct xonar_generic generic; | 71 | struct xonar_generic generic; |
72 | u8 cs4398_regs[7]; | 72 | u8 cs4398_regs[8]; |
73 | u8 cs4362a_regs[15]; | 73 | u8 cs4362a_regs[15]; |
74 | }; | 74 | }; |
75 | 75 | ||
@@ -121,12 +121,11 @@ static void cs43xx_registers_init(struct oxygen *chip) | |||
121 | cs4398_write(chip, 4, data->cs4398_regs[4]); | 121 | cs4398_write(chip, 4, data->cs4398_regs[4]); |
122 | cs4398_write(chip, 5, data->cs4398_regs[5]); | 122 | cs4398_write(chip, 5, data->cs4398_regs[5]); |
123 | cs4398_write(chip, 6, data->cs4398_regs[6]); | 123 | cs4398_write(chip, 6, data->cs4398_regs[6]); |
124 | cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | | 124 | cs4398_write(chip, 7, data->cs4398_regs[7]); |
125 | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); | ||
126 | cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); | 125 | cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); |
127 | cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE | | 126 | cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE | |
128 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); | 127 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); |
129 | cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); | 128 | cs4362a_write(chip, 0x04, data->cs4362a_regs[0x04]); |
130 | cs4362a_write(chip, 0x05, 0); | 129 | cs4362a_write(chip, 0x05, 0); |
131 | for (i = 6; i <= 14; ++i) | 130 | for (i = 6; i <= 14; ++i) |
132 | cs4362a_write(chip, i, data->cs4362a_regs[i]); | 131 | cs4362a_write(chip, i, data->cs4362a_regs[i]); |
@@ -147,6 +146,9 @@ static void xonar_d1_init(struct oxygen *chip) | |||
147 | CS4398_MUTE_B | CS4398_MUTE_A | CS4398_PAMUTE; | 146 | CS4398_MUTE_B | CS4398_MUTE_A | CS4398_PAMUTE; |
148 | data->cs4398_regs[5] = 60 * 2; | 147 | data->cs4398_regs[5] = 60 * 2; |
149 | data->cs4398_regs[6] = 60 * 2; | 148 | data->cs4398_regs[6] = 60 * 2; |
149 | data->cs4398_regs[7] = CS4398_RMP_DN | CS4398_RMP_UP | | ||
150 | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP; | ||
151 | data->cs4362a_regs[4] = CS4362A_RMP_DN | CS4362A_DEM_NONE; | ||
150 | data->cs4362a_regs[6] = CS4362A_FM_SINGLE | | 152 | data->cs4362a_regs[6] = CS4362A_FM_SINGLE | |
151 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | 153 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; |
152 | data->cs4362a_regs[7] = 60 | CS4362A_MUTE; | 154 | data->cs4362a_regs[7] = 60 | CS4362A_MUTE; |
@@ -286,6 +288,68 @@ static const struct snd_kcontrol_new front_panel_switch = { | |||
286 | .private_value = GPIO_D1_FRONT_PANEL, | 288 | .private_value = GPIO_D1_FRONT_PANEL, |
287 | }; | 289 | }; |
288 | 290 | ||
291 | static int rolloff_info(struct snd_kcontrol *ctl, | ||
292 | struct snd_ctl_elem_info *info) | ||
293 | { | ||
294 | static const char *const names[2] = { | ||
295 | "Fast Roll-off", "Slow Roll-off" | ||
296 | }; | ||
297 | |||
298 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
299 | info->count = 1; | ||
300 | info->value.enumerated.items = 2; | ||
301 | if (info->value.enumerated.item >= 2) | ||
302 | info->value.enumerated.item = 1; | ||
303 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int rolloff_get(struct snd_kcontrol *ctl, | ||
308 | struct snd_ctl_elem_value *value) | ||
309 | { | ||
310 | struct oxygen *chip = ctl->private_data; | ||
311 | struct xonar_cs43xx *data = chip->model_data; | ||
312 | |||
313 | value->value.enumerated.item[0] = | ||
314 | (data->cs4398_regs[7] & CS4398_FILT_SEL) != 0; | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int rolloff_put(struct snd_kcontrol *ctl, | ||
319 | struct snd_ctl_elem_value *value) | ||
320 | { | ||
321 | struct oxygen *chip = ctl->private_data; | ||
322 | struct xonar_cs43xx *data = chip->model_data; | ||
323 | int changed; | ||
324 | u8 reg; | ||
325 | |||
326 | mutex_lock(&chip->mutex); | ||
327 | reg = data->cs4398_regs[7]; | ||
328 | if (value->value.enumerated.item[0]) | ||
329 | reg |= CS4398_FILT_SEL; | ||
330 | else | ||
331 | reg &= ~CS4398_FILT_SEL; | ||
332 | changed = reg != data->cs4398_regs[7]; | ||
333 | if (changed) { | ||
334 | cs4398_write(chip, 7, reg); | ||
335 | if (reg & CS4398_FILT_SEL) | ||
336 | reg = data->cs4362a_regs[0x04] | CS4362A_FILT_SEL; | ||
337 | else | ||
338 | reg = data->cs4362a_regs[0x04] & ~CS4362A_FILT_SEL; | ||
339 | cs4362a_write(chip, 0x04, reg); | ||
340 | } | ||
341 | mutex_unlock(&chip->mutex); | ||
342 | return changed; | ||
343 | } | ||
344 | |||
345 | static const struct snd_kcontrol_new rolloff_control = { | ||
346 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
347 | .name = "DAC Filter Playback Enum", | ||
348 | .info = rolloff_info, | ||
349 | .get = rolloff_get, | ||
350 | .put = rolloff_put, | ||
351 | }; | ||
352 | |||
289 | static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, | 353 | static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, |
290 | unsigned int reg, unsigned int mute) | 354 | unsigned int reg, unsigned int mute) |
291 | { | 355 | { |
@@ -309,7 +373,15 @@ static int xonar_d1_control_filter(struct snd_kcontrol_new *template) | |||
309 | 373 | ||
310 | static int xonar_d1_mixer_init(struct oxygen *chip) | 374 | static int xonar_d1_mixer_init(struct oxygen *chip) |
311 | { | 375 | { |
312 | return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); | 376 | int err; |
377 | |||
378 | err = snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); | ||
379 | if (err < 0) | ||
380 | return err; | ||
381 | err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | ||
382 | if (err < 0) | ||
383 | return err; | ||
384 | return 0; | ||
313 | } | 385 | } |
314 | 386 | ||
315 | static const struct oxygen_model model_xonar_d1 = { | 387 | static const struct oxygen_model model_xonar_d1 = { |
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 7f153fb1848d..ba18fb546b4f 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c | |||
@@ -265,7 +265,8 @@ static void pcm1796_registers_init(struct oxygen *chip) | |||
265 | + gain_offset); | 265 | + gain_offset); |
266 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1] | 266 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1] |
267 | + gain_offset); | 267 | + gain_offset); |
268 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); | 268 | pcm1796_write(chip, i, 19, |
269 | data->pcm1796_regs[0][19 - PCM1796_REG_BASE]); | ||
269 | pcm1796_write(chip, i, 20, | 270 | pcm1796_write(chip, i, 20, |
270 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); | 271 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); |
271 | pcm1796_write(chip, i, 21, 0); | 272 | pcm1796_write(chip, i, 21, 0); |
@@ -278,6 +279,8 @@ static void pcm1796_init(struct oxygen *chip) | |||
278 | 279 | ||
279 | data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | | 280 | data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | |
280 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | 281 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; |
282 | data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = | ||
283 | PCM1796_FLT_SHARP | PCM1796_ATS_1; | ||
281 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; | 284 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; |
282 | pcm1796_registers_init(chip); | 285 | pcm1796_registers_init(chip); |
283 | data->current_rate = 48000; | 286 | data->current_rate = 48000; |
@@ -642,6 +645,67 @@ static const struct snd_kcontrol_new alt_switch = { | |||
642 | .private_value = GPIO_D2_ALT, | 645 | .private_value = GPIO_D2_ALT, |
643 | }; | 646 | }; |
644 | 647 | ||
648 | static int rolloff_info(struct snd_kcontrol *ctl, | ||
649 | struct snd_ctl_elem_info *info) | ||
650 | { | ||
651 | static const char *const names[2] = { | ||
652 | "Sharp Roll-off", "Slow Roll-off" | ||
653 | }; | ||
654 | |||
655 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
656 | info->count = 1; | ||
657 | info->value.enumerated.items = 2; | ||
658 | if (info->value.enumerated.item >= 2) | ||
659 | info->value.enumerated.item = 1; | ||
660 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | static int rolloff_get(struct snd_kcontrol *ctl, | ||
665 | struct snd_ctl_elem_value *value) | ||
666 | { | ||
667 | struct oxygen *chip = ctl->private_data; | ||
668 | struct xonar_pcm179x *data = chip->model_data; | ||
669 | |||
670 | value->value.enumerated.item[0] = | ||
671 | (data->pcm1796_regs[0][19 - PCM1796_REG_BASE] & | ||
672 | PCM1796_FLT_MASK) != PCM1796_FLT_SHARP; | ||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | static int rolloff_put(struct snd_kcontrol *ctl, | ||
677 | struct snd_ctl_elem_value *value) | ||
678 | { | ||
679 | struct oxygen *chip = ctl->private_data; | ||
680 | struct xonar_pcm179x *data = chip->model_data; | ||
681 | unsigned int i; | ||
682 | int changed; | ||
683 | u8 reg; | ||
684 | |||
685 | mutex_lock(&chip->mutex); | ||
686 | reg = data->pcm1796_regs[0][19 - PCM1796_REG_BASE]; | ||
687 | reg &= ~PCM1796_FLT_MASK; | ||
688 | if (!value->value.enumerated.item[0]) | ||
689 | reg |= PCM1796_FLT_SHARP; | ||
690 | else | ||
691 | reg |= PCM1796_FLT_SLOW; | ||
692 | changed = reg != data->pcm1796_regs[0][19 - PCM1796_REG_BASE]; | ||
693 | if (changed) { | ||
694 | for (i = 0; i < data->dacs; ++i) | ||
695 | pcm1796_write(chip, i, 19, reg); | ||
696 | } | ||
697 | mutex_unlock(&chip->mutex); | ||
698 | return changed; | ||
699 | } | ||
700 | |||
701 | static const struct snd_kcontrol_new rolloff_control = { | ||
702 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
703 | .name = "DAC Filter Playback Enum", | ||
704 | .info = rolloff_info, | ||
705 | .get = rolloff_get, | ||
706 | .put = rolloff_put, | ||
707 | }; | ||
708 | |||
645 | static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | 709 | static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) |
646 | { | 710 | { |
647 | static const char *const names[2] = { "64x", "128x" }; | 711 | static const char *const names[2] = { "64x", "128x" }; |
@@ -858,6 +922,19 @@ static int xonar_st_control_filter(struct snd_kcontrol_new *template) | |||
858 | return 0; | 922 | return 0; |
859 | } | 923 | } |
860 | 924 | ||
925 | static int add_pcm1796_controls(struct oxygen *chip) | ||
926 | { | ||
927 | int err; | ||
928 | |||
929 | err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | ||
930 | if (err < 0) | ||
931 | return err; | ||
932 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | ||
933 | if (err < 0) | ||
934 | return err; | ||
935 | return 0; | ||
936 | } | ||
937 | |||
861 | static int xonar_d2_mixer_init(struct oxygen *chip) | 938 | static int xonar_d2_mixer_init(struct oxygen *chip) |
862 | { | 939 | { |
863 | int err; | 940 | int err; |
@@ -865,7 +942,7 @@ static int xonar_d2_mixer_init(struct oxygen *chip) | |||
865 | err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); | 942 | err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); |
866 | if (err < 0) | 943 | if (err < 0) |
867 | return err; | 944 | return err; |
868 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | 945 | err = add_pcm1796_controls(chip); |
869 | if (err < 0) | 946 | if (err < 0) |
870 | return err; | 947 | return err; |
871 | return 0; | 948 | return 0; |
@@ -873,7 +950,7 @@ static int xonar_d2_mixer_init(struct oxygen *chip) | |||
873 | 950 | ||
874 | static int xonar_hdav_mixer_init(struct oxygen *chip) | 951 | static int xonar_hdav_mixer_init(struct oxygen *chip) |
875 | { | 952 | { |
876 | return snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | 953 | return add_pcm1796_controls(chip); |
877 | } | 954 | } |
878 | 955 | ||
879 | static int xonar_st_mixer_init(struct oxygen *chip) | 956 | static int xonar_st_mixer_init(struct oxygen *chip) |
@@ -887,7 +964,7 @@ static int xonar_st_mixer_init(struct oxygen *chip) | |||
887 | if (err < 0) | 964 | if (err < 0) |
888 | return err; | 965 | return err; |
889 | } | 966 | } |
890 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | 967 | err = add_pcm1796_controls(chip); |
891 | if (err < 0) | 968 | if (err < 0) |
892 | return err; | 969 | return err; |
893 | return 0; | 970 | return 0; |