diff options
author | Matthew Ranostay <mranostay@embeddedalley.com> | 2008-09-11 09:49:39 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-09-23 02:17:56 -0400 |
commit | 89385035fa3126dff27bfb73d186bc51e78d5ba5 (patch) | |
tree | 6d46bca88b7719546d10b9a304f153e365e84e51 /sound | |
parent | 6a14f58518dd18d315eaa6e4ca38bc6b051927af (diff) |
ALSA: hda: Input port AMP controls
Added support for controlling hardware gain amps on input ports
using a volume control mixer with a mux selecting the port being controlled.
Signed-off-by: Matthew Ranostay <mranostay@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 9 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 9 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 138 |
3 files changed, 145 insertions, 11 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 531364d35353..c742e101d91e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -961,15 +961,6 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) | |||
961 | } | 961 | } |
962 | #endif /* SND_HDA_NEEDS_RESUME */ | 962 | #endif /* SND_HDA_NEEDS_RESUME */ |
963 | 963 | ||
964 | /* | ||
965 | * AMP control callbacks | ||
966 | */ | ||
967 | /* retrieve parameters from private_value */ | ||
968 | #define get_amp_nid(kc) ((kc)->private_value & 0xffff) | ||
969 | #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) | ||
970 | #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) | ||
971 | #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) | ||
972 | |||
973 | /* volume */ | 964 | /* volume */ |
974 | int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | 965 | int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, |
975 | struct snd_ctl_elem_info *uinfo) | 966 | struct snd_ctl_elem_info *uinfo) |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5c9e578f7f2d..d688f50cdfce 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -418,4 +418,13 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, | |||
418 | hda_nid_t nid); | 418 | hda_nid_t nid); |
419 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ | 419 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ |
420 | 420 | ||
421 | /* | ||
422 | * AMP control callbacks | ||
423 | */ | ||
424 | /* retrieve parameters from private_value */ | ||
425 | #define get_amp_nid(kc) ((kc)->private_value & 0xffff) | ||
426 | #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) | ||
427 | #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) | ||
428 | #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) | ||
429 | |||
421 | #endif /* __SOUND_HDA_LOCAL_H */ | 430 | #endif /* __SOUND_HDA_LOCAL_H */ |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 9744ae31dc73..d3c88c269da0 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -157,10 +157,13 @@ struct sigmatel_spec { | |||
157 | unsigned int num_pwrs; | 157 | unsigned int num_pwrs; |
158 | unsigned int *pwr_mapping; | 158 | unsigned int *pwr_mapping; |
159 | hda_nid_t *pwr_nids; | 159 | hda_nid_t *pwr_nids; |
160 | hda_nid_t *amp_nids; | ||
160 | hda_nid_t *dac_list; | 161 | hda_nid_t *dac_list; |
161 | 162 | ||
162 | /* playback */ | 163 | /* playback */ |
163 | struct hda_input_mux *mono_mux; | 164 | struct hda_input_mux *mono_mux; |
165 | struct hda_input_mux *amp_mux; | ||
166 | unsigned int cur_amux; | ||
164 | unsigned int cur_mmux; | 167 | unsigned int cur_mmux; |
165 | struct hda_multi_out multiout; | 168 | struct hda_multi_out multiout; |
166 | hda_nid_t dac_nids[5]; | 169 | hda_nid_t dac_nids[5]; |
@@ -216,6 +219,7 @@ struct sigmatel_spec { | |||
216 | struct hda_input_mux private_dimux; | 219 | struct hda_input_mux private_dimux; |
217 | struct hda_input_mux private_imux; | 220 | struct hda_input_mux private_imux; |
218 | struct hda_input_mux private_smux; | 221 | struct hda_input_mux private_smux; |
222 | struct hda_input_mux private_amp_mux; | ||
219 | struct hda_input_mux private_mono_mux; | 223 | struct hda_input_mux private_mono_mux; |
220 | }; | 224 | }; |
221 | 225 | ||
@@ -244,6 +248,10 @@ static hda_nid_t stac92hd73xx_adc_nids[2] = { | |||
244 | 0x1a, 0x1b | 248 | 0x1a, 0x1b |
245 | }; | 249 | }; |
246 | 250 | ||
251 | static hda_nid_t stac92hd73xx_amp_nids[4] = { | ||
252 | 0x0b, 0x0c, 0x0e, 0 | ||
253 | }; | ||
254 | |||
247 | #define STAC92HD73XX_NUM_DMICS 2 | 255 | #define STAC92HD73XX_NUM_DMICS 2 |
248 | static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { | 256 | static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { |
249 | 0x13, 0x14, 0 | 257 | 0x13, 0x14, 0 |
@@ -449,6 +457,34 @@ static hda_nid_t stac9205_pin_nids[12] = { | |||
449 | 0x21, 0x22, | 457 | 0x21, 0x22, |
450 | }; | 458 | }; |
451 | 459 | ||
460 | #define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info | ||
461 | |||
462 | static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol, | ||
463 | struct snd_ctl_elem_value *ucontrol) | ||
464 | { | ||
465 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
466 | struct sigmatel_spec *spec = codec->spec; | ||
467 | hda_nid_t nid = spec->amp_nids[spec->cur_amux]; | ||
468 | |||
469 | kcontrol->private_value ^= get_amp_nid(kcontrol); | ||
470 | kcontrol->private_value |= nid; | ||
471 | |||
472 | return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); | ||
473 | } | ||
474 | |||
475 | static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol, | ||
476 | struct snd_ctl_elem_value *ucontrol) | ||
477 | { | ||
478 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
479 | struct sigmatel_spec *spec = codec->spec; | ||
480 | hda_nid_t nid = spec->amp_nids[spec->cur_amux]; | ||
481 | |||
482 | kcontrol->private_value ^= get_amp_nid(kcontrol); | ||
483 | kcontrol->private_value |= nid; | ||
484 | |||
485 | return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); | ||
486 | } | ||
487 | |||
452 | static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol, | 488 | static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol, |
453 | struct snd_ctl_elem_info *uinfo) | 489 | struct snd_ctl_elem_info *uinfo) |
454 | { | 490 | { |
@@ -564,6 +600,41 @@ static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
564 | spec->mono_nid, &spec->cur_mmux); | 600 | spec->mono_nid, &spec->cur_mmux); |
565 | } | 601 | } |
566 | 602 | ||
603 | static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
604 | struct snd_ctl_elem_info *uinfo) | ||
605 | { | ||
606 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
607 | struct sigmatel_spec *spec = codec->spec; | ||
608 | return snd_hda_input_mux_info(spec->amp_mux, uinfo); | ||
609 | } | ||
610 | |||
611 | static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
612 | struct snd_ctl_elem_value *ucontrol) | ||
613 | { | ||
614 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
615 | struct sigmatel_spec *spec = codec->spec; | ||
616 | |||
617 | ucontrol->value.enumerated.item[0] = spec->cur_amux; | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
622 | struct snd_ctl_elem_value *ucontrol) | ||
623 | { | ||
624 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
625 | struct sigmatel_spec *spec = codec->spec; | ||
626 | struct snd_kcontrol *ctl = | ||
627 | snd_hda_find_mixer_ctl(codec, "Amp Capture Volume"); | ||
628 | if (!ctl) | ||
629 | return -EINVAL; | ||
630 | |||
631 | snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE | | ||
632 | SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); | ||
633 | |||
634 | return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol, | ||
635 | 0, &spec->cur_amux); | ||
636 | } | ||
637 | |||
567 | #define stac92xx_aloopback_info snd_ctl_boolean_mono_info | 638 | #define stac92xx_aloopback_info snd_ctl_boolean_mono_info |
568 | 639 | ||
569 | static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, | 640 | static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, |
@@ -838,6 +909,31 @@ static struct hda_verb stac9205_core_init[] = { | |||
838 | .put = stac92xx_mono_mux_enum_put, \ | 909 | .put = stac92xx_mono_mux_enum_put, \ |
839 | } | 910 | } |
840 | 911 | ||
912 | #define STAC_AMP_MUX \ | ||
913 | { \ | ||
914 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
915 | .name = "Amp Selector Capture Switch", \ | ||
916 | .count = 1, \ | ||
917 | .info = stac92xx_amp_mux_enum_info, \ | ||
918 | .get = stac92xx_amp_mux_enum_get, \ | ||
919 | .put = stac92xx_amp_mux_enum_put, \ | ||
920 | } | ||
921 | |||
922 | #define STAC_AMP_VOL(xname, nid, chs, idx, dir) \ | ||
923 | { \ | ||
924 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
925 | .name = xname, \ | ||
926 | .index = 0, \ | ||
927 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
928 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
929 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | ||
930 | .info = stac92xx_amp_volume_info, \ | ||
931 | .get = stac92xx_amp_volume_get, \ | ||
932 | .put = stac92xx_amp_volume_put, \ | ||
933 | .tlv = { .c = snd_hda_mixer_amp_tlv }, \ | ||
934 | .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \ | ||
935 | } | ||
936 | |||
841 | #define STAC_INPUT_SOURCE(cnt) \ | 937 | #define STAC_INPUT_SOURCE(cnt) \ |
842 | { \ | 938 | { \ |
843 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 939 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
@@ -2421,6 +2517,8 @@ enum { | |||
2421 | STAC_CTL_WIDGET_VOL, | 2517 | STAC_CTL_WIDGET_VOL, |
2422 | STAC_CTL_WIDGET_MUTE, | 2518 | STAC_CTL_WIDGET_MUTE, |
2423 | STAC_CTL_WIDGET_MONO_MUX, | 2519 | STAC_CTL_WIDGET_MONO_MUX, |
2520 | STAC_CTL_WIDGET_AMP_MUX, | ||
2521 | STAC_CTL_WIDGET_AMP_VOL, | ||
2424 | STAC_CTL_WIDGET_HP_SWITCH, | 2522 | STAC_CTL_WIDGET_HP_SWITCH, |
2425 | STAC_CTL_WIDGET_IO_SWITCH, | 2523 | STAC_CTL_WIDGET_IO_SWITCH, |
2426 | STAC_CTL_WIDGET_CLFE_SWITCH | 2524 | STAC_CTL_WIDGET_CLFE_SWITCH |
@@ -2430,6 +2528,8 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = { | |||
2430 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | 2528 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), |
2431 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | 2529 | HDA_CODEC_MUTE(NULL, 0, 0, 0), |
2432 | STAC_MONO_MUX, | 2530 | STAC_MONO_MUX, |
2531 | STAC_AMP_MUX, | ||
2532 | STAC_AMP_VOL(NULL, 0, 0, 0, 0), | ||
2433 | STAC_CODEC_HP_SWITCH(NULL), | 2533 | STAC_CODEC_HP_SWITCH(NULL), |
2434 | STAC_CODEC_IO_SWITCH(NULL, 0), | 2534 | STAC_CODEC_IO_SWITCH(NULL, 0), |
2435 | STAC_CODEC_CLFE_SWITCH(NULL, 0), | 2535 | STAC_CODEC_CLFE_SWITCH(NULL, 0), |
@@ -2847,6 +2947,35 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec) | |||
2847 | "Mono Mux", spec->mono_nid); | 2947 | "Mono Mux", spec->mono_nid); |
2848 | } | 2948 | } |
2849 | 2949 | ||
2950 | /* labels for amp mux outputs */ | ||
2951 | static const char *stac92xx_amp_labels[3] = { | ||
2952 | "Front Microphone", "Microphone", "Line In" | ||
2953 | }; | ||
2954 | |||
2955 | /* create amp out controls mux on capable codecs */ | ||
2956 | static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec) | ||
2957 | { | ||
2958 | struct sigmatel_spec *spec = codec->spec; | ||
2959 | struct hda_input_mux *amp_mux = &spec->private_amp_mux; | ||
2960 | int i, err; | ||
2961 | |||
2962 | for (i = 0; i < ARRAY_SIZE(stac92xx_amp_labels); i++) { | ||
2963 | amp_mux->items[amp_mux->num_items].label = | ||
2964 | stac92xx_amp_labels[i]; | ||
2965 | amp_mux->items[amp_mux->num_items].index = i; | ||
2966 | amp_mux->num_items++; | ||
2967 | } | ||
2968 | |||
2969 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX, | ||
2970 | "Amp Selector Capture Switch", 0); | ||
2971 | if (err < 0) | ||
2972 | return err; | ||
2973 | return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL, | ||
2974 | "Amp Capture Volume", | ||
2975 | HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT)); | ||
2976 | } | ||
2977 | |||
2978 | |||
2850 | /* create PC beep volume controls */ | 2979 | /* create PC beep volume controls */ |
2851 | static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, | 2980 | static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, |
2852 | hda_nid_t nid) | 2981 | hda_nid_t nid) |
@@ -3216,7 +3345,11 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
3216 | if (err < 0) | 3345 | if (err < 0) |
3217 | return err; | 3346 | return err; |
3218 | } | 3347 | } |
3219 | 3348 | if (spec->amp_nids) { | |
3349 | err = stac92xx_auto_create_amp_output_ctls(codec); | ||
3350 | if (err < 0) | ||
3351 | return err; | ||
3352 | } | ||
3220 | if (spec->num_dmics > 0) | 3353 | if (spec->num_dmics > 0) |
3221 | if ((err = stac92xx_auto_create_dmic_input_ctls(codec, | 3354 | if ((err = stac92xx_auto_create_dmic_input_ctls(codec, |
3222 | &spec->autocfg)) < 0) | 3355 | &spec->autocfg)) < 0) |
@@ -3249,7 +3382,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
3249 | spec->dinput_mux = &spec->private_dimux; | 3382 | spec->dinput_mux = &spec->private_dimux; |
3250 | spec->sinput_mux = &spec->private_smux; | 3383 | spec->sinput_mux = &spec->private_smux; |
3251 | spec->mono_mux = &spec->private_mono_mux; | 3384 | spec->mono_mux = &spec->private_mono_mux; |
3252 | 3385 | spec->amp_mux = &spec->private_amp_mux; | |
3253 | return 1; | 3386 | return 1; |
3254 | } | 3387 | } |
3255 | 3388 | ||
@@ -3917,6 +4050,7 @@ again: | |||
3917 | spec->dmic_nids = stac92hd73xx_dmic_nids; | 4050 | spec->dmic_nids = stac92hd73xx_dmic_nids; |
3918 | spec->dmux_nids = stac92hd73xx_dmux_nids; | 4051 | spec->dmux_nids = stac92hd73xx_dmux_nids; |
3919 | spec->smux_nids = stac92hd73xx_smux_nids; | 4052 | spec->smux_nids = stac92hd73xx_smux_nids; |
4053 | spec->amp_nids = stac92hd73xx_amp_nids; | ||
3920 | 4054 | ||
3921 | spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); | 4055 | spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); |
3922 | spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); | 4056 | spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); |