diff options
Diffstat (limited to 'sound/pci/hda/patch_sigmatel.c')
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 143 |
1 files changed, 106 insertions, 37 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ec25262e59e7..6b0bc040c3b1 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -93,6 +93,7 @@ enum { | |||
93 | STAC_92HD83XXX_REF, | 93 | STAC_92HD83XXX_REF, |
94 | STAC_92HD83XXX_PWR_REF, | 94 | STAC_92HD83XXX_PWR_REF, |
95 | STAC_DELL_S14, | 95 | STAC_DELL_S14, |
96 | STAC_92HD83XXX_HP, | ||
96 | STAC_92HD83XXX_MODELS | 97 | STAC_92HD83XXX_MODELS |
97 | }; | 98 | }; |
98 | 99 | ||
@@ -1085,7 +1086,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) | |||
1085 | if (!spec->auto_mic && spec->num_dmuxes > 0 && | 1086 | if (!spec->auto_mic && spec->num_dmuxes > 0 && |
1086 | snd_hda_get_bool_hint(codec, "separate_dmux") == 1) { | 1087 | snd_hda_get_bool_hint(codec, "separate_dmux") == 1) { |
1087 | stac_dmux_mixer.count = spec->num_dmuxes; | 1088 | stac_dmux_mixer.count = spec->num_dmuxes; |
1088 | err = snd_hda_ctl_add(codec, | 1089 | err = snd_hda_ctl_add(codec, 0, |
1089 | snd_ctl_new1(&stac_dmux_mixer, codec)); | 1090 | snd_ctl_new1(&stac_dmux_mixer, codec)); |
1090 | if (err < 0) | 1091 | if (err < 0) |
1091 | return err; | 1092 | return err; |
@@ -1101,7 +1102,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) | |||
1101 | spec->spdif_mute = 1; | 1102 | spec->spdif_mute = 1; |
1102 | } | 1103 | } |
1103 | stac_smux_mixer.count = spec->num_smuxes; | 1104 | stac_smux_mixer.count = spec->num_smuxes; |
1104 | err = snd_hda_ctl_add(codec, | 1105 | err = snd_hda_ctl_add(codec, 0, |
1105 | snd_ctl_new1(&stac_smux_mixer, codec)); | 1106 | snd_ctl_new1(&stac_smux_mixer, codec)); |
1106 | if (err < 0) | 1107 | if (err < 0) |
1107 | return err; | 1108 | return err; |
@@ -1624,6 +1625,7 @@ static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { | |||
1624 | [STAC_92HD83XXX_REF] = "ref", | 1625 | [STAC_92HD83XXX_REF] = "ref", |
1625 | [STAC_92HD83XXX_PWR_REF] = "mic-ref", | 1626 | [STAC_92HD83XXX_PWR_REF] = "mic-ref", |
1626 | [STAC_DELL_S14] = "dell-s14", | 1627 | [STAC_DELL_S14] = "dell-s14", |
1628 | [STAC_92HD83XXX_HP] = "hp", | ||
1627 | }; | 1629 | }; |
1628 | 1630 | ||
1629 | static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { | 1631 | static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { |
@@ -1634,6 +1636,8 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { | |||
1634 | "DFI LanParty", STAC_92HD83XXX_REF), | 1636 | "DFI LanParty", STAC_92HD83XXX_REF), |
1635 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, | 1637 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, |
1636 | "unknown Dell", STAC_DELL_S14), | 1638 | "unknown Dell", STAC_DELL_S14), |
1639 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600, | ||
1640 | "HP", STAC_92HD83XXX_HP), | ||
1637 | {} /* terminator */ | 1641 | {} /* terminator */ |
1638 | }; | 1642 | }; |
1639 | 1643 | ||
@@ -2648,6 +2652,7 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, | |||
2648 | enum { | 2652 | enum { |
2649 | STAC_CTL_WIDGET_VOL, | 2653 | STAC_CTL_WIDGET_VOL, |
2650 | STAC_CTL_WIDGET_MUTE, | 2654 | STAC_CTL_WIDGET_MUTE, |
2655 | STAC_CTL_WIDGET_MUTE_BEEP, | ||
2651 | STAC_CTL_WIDGET_MONO_MUX, | 2656 | STAC_CTL_WIDGET_MONO_MUX, |
2652 | STAC_CTL_WIDGET_HP_SWITCH, | 2657 | STAC_CTL_WIDGET_HP_SWITCH, |
2653 | STAC_CTL_WIDGET_IO_SWITCH, | 2658 | STAC_CTL_WIDGET_IO_SWITCH, |
@@ -2658,6 +2663,7 @@ enum { | |||
2658 | static struct snd_kcontrol_new stac92xx_control_templates[] = { | 2663 | static struct snd_kcontrol_new stac92xx_control_templates[] = { |
2659 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | 2664 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), |
2660 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | 2665 | HDA_CODEC_MUTE(NULL, 0, 0, 0), |
2666 | HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0), | ||
2661 | STAC_MONO_MUX, | 2667 | STAC_MONO_MUX, |
2662 | STAC_CODEC_HP_SWITCH(NULL), | 2668 | STAC_CODEC_HP_SWITCH(NULL), |
2663 | STAC_CODEC_IO_SWITCH(NULL, 0), | 2669 | STAC_CODEC_IO_SWITCH(NULL, 0), |
@@ -2669,7 +2675,8 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = { | |||
2669 | static struct snd_kcontrol_new * | 2675 | static struct snd_kcontrol_new * |
2670 | stac_control_new(struct sigmatel_spec *spec, | 2676 | stac_control_new(struct sigmatel_spec *spec, |
2671 | struct snd_kcontrol_new *ktemp, | 2677 | struct snd_kcontrol_new *ktemp, |
2672 | const char *name) | 2678 | const char *name, |
2679 | hda_nid_t nid) | ||
2673 | { | 2680 | { |
2674 | struct snd_kcontrol_new *knew; | 2681 | struct snd_kcontrol_new *knew; |
2675 | 2682 | ||
@@ -2685,6 +2692,8 @@ stac_control_new(struct sigmatel_spec *spec, | |||
2685 | spec->kctls.alloced--; | 2692 | spec->kctls.alloced--; |
2686 | return NULL; | 2693 | return NULL; |
2687 | } | 2694 | } |
2695 | if (nid) | ||
2696 | knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; | ||
2688 | return knew; | 2697 | return knew; |
2689 | } | 2698 | } |
2690 | 2699 | ||
@@ -2693,7 +2702,8 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec, | |||
2693 | int idx, const char *name, | 2702 | int idx, const char *name, |
2694 | unsigned long val) | 2703 | unsigned long val) |
2695 | { | 2704 | { |
2696 | struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name); | 2705 | struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, |
2706 | get_amp_nid_(val)); | ||
2697 | if (!knew) | 2707 | if (!knew) |
2698 | return -ENOMEM; | 2708 | return -ENOMEM; |
2699 | knew->index = idx; | 2709 | knew->index = idx; |
@@ -2764,7 +2774,7 @@ static int stac92xx_add_input_source(struct sigmatel_spec *spec) | |||
2764 | if (!spec->num_adcs || imux->num_items <= 1) | 2774 | if (!spec->num_adcs || imux->num_items <= 1) |
2765 | return 0; /* no need for input source control */ | 2775 | return 0; /* no need for input source control */ |
2766 | knew = stac_control_new(spec, &stac_input_src_temp, | 2776 | knew = stac_control_new(spec, &stac_input_src_temp, |
2767 | stac_input_src_temp.name); | 2777 | stac_input_src_temp.name, 0); |
2768 | if (!knew) | 2778 | if (!knew) |
2769 | return -ENOMEM; | 2779 | return -ENOMEM; |
2770 | knew->count = spec->num_adcs; | 2780 | knew->count = spec->num_adcs; |
@@ -3221,11 +3231,14 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, | |||
3221 | { | 3231 | { |
3222 | struct sigmatel_spec *spec = codec->spec; | 3232 | struct sigmatel_spec *spec = codec->spec; |
3223 | u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); | 3233 | u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); |
3224 | int err; | 3234 | int err, type = STAC_CTL_WIDGET_MUTE_BEEP; |
3235 | |||
3236 | if (spec->anabeep_nid == nid) | ||
3237 | type = STAC_CTL_WIDGET_MUTE; | ||
3225 | 3238 | ||
3226 | /* check for mute support for the the amp */ | 3239 | /* check for mute support for the the amp */ |
3227 | if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { | 3240 | if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { |
3228 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, | 3241 | err = stac92xx_add_control(spec, type, |
3229 | "Beep Playback Switch", | 3242 | "Beep Playback Switch", |
3230 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); | 3243 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); |
3231 | if (err < 0) | 3244 | if (err < 0) |
@@ -3258,12 +3271,7 @@ static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol, | |||
3258 | struct snd_ctl_elem_value *ucontrol) | 3271 | struct snd_ctl_elem_value *ucontrol) |
3259 | { | 3272 | { |
3260 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 3273 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
3261 | int enabled = !!ucontrol->value.integer.value[0]; | 3274 | return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]); |
3262 | if (codec->beep->enabled != enabled) { | ||
3263 | codec->beep->enabled = enabled; | ||
3264 | return 1; | ||
3265 | } | ||
3266 | return 0; | ||
3267 | } | 3275 | } |
3268 | 3276 | ||
3269 | static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { | 3277 | static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { |
@@ -3631,6 +3639,26 @@ static void stac92xx_auto_init_hp_out(struct hda_codec *codec) | |||
3631 | } | 3639 | } |
3632 | } | 3640 | } |
3633 | 3641 | ||
3642 | static int is_dual_headphones(struct hda_codec *codec) | ||
3643 | { | ||
3644 | struct sigmatel_spec *spec = codec->spec; | ||
3645 | int i, valid_hps; | ||
3646 | |||
3647 | if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT || | ||
3648 | spec->autocfg.hp_outs <= 1) | ||
3649 | return 0; | ||
3650 | valid_hps = 0; | ||
3651 | for (i = 0; i < spec->autocfg.hp_outs; i++) { | ||
3652 | hda_nid_t nid = spec->autocfg.hp_pins[i]; | ||
3653 | unsigned int cfg = snd_hda_codec_get_pincfg(codec, nid); | ||
3654 | if (get_defcfg_location(cfg) & AC_JACK_LOC_SEPARATE) | ||
3655 | continue; | ||
3656 | valid_hps++; | ||
3657 | } | ||
3658 | return (valid_hps > 1); | ||
3659 | } | ||
3660 | |||
3661 | |||
3634 | static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) | 3662 | static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) |
3635 | { | 3663 | { |
3636 | struct sigmatel_spec *spec = codec->spec; | 3664 | struct sigmatel_spec *spec = codec->spec; |
@@ -3647,8 +3675,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
3647 | /* If we have no real line-out pin and multiple hp-outs, HPs should | 3675 | /* If we have no real line-out pin and multiple hp-outs, HPs should |
3648 | * be set up as multi-channel outputs. | 3676 | * be set up as multi-channel outputs. |
3649 | */ | 3677 | */ |
3650 | if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && | 3678 | if (is_dual_headphones(codec)) { |
3651 | spec->autocfg.hp_outs > 1) { | ||
3652 | /* Copy hp_outs to line_outs, backup line_outs in | 3679 | /* Copy hp_outs to line_outs, backup line_outs in |
3653 | * speaker_outs so that the following routines can handle | 3680 | * speaker_outs so that the following routines can handle |
3654 | * HP pins as primary outputs. | 3681 | * HP pins as primary outputs. |
@@ -4329,6 +4356,28 @@ static void stac92xx_free_kctls(struct hda_codec *codec) | |||
4329 | snd_array_free(&spec->kctls); | 4356 | snd_array_free(&spec->kctls); |
4330 | } | 4357 | } |
4331 | 4358 | ||
4359 | static void stac92xx_shutup(struct hda_codec *codec) | ||
4360 | { | ||
4361 | struct sigmatel_spec *spec = codec->spec; | ||
4362 | int i; | ||
4363 | hda_nid_t nid; | ||
4364 | |||
4365 | /* reset each pin before powering down DAC/ADC to avoid click noise */ | ||
4366 | nid = codec->start_nid; | ||
4367 | for (i = 0; i < codec->num_nodes; i++, nid++) { | ||
4368 | unsigned int wcaps = get_wcaps(codec, nid); | ||
4369 | unsigned int wid_type = get_wcaps_type(wcaps); | ||
4370 | if (wid_type == AC_WID_PIN) | ||
4371 | snd_hda_codec_read(codec, nid, 0, | ||
4372 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
4373 | } | ||
4374 | |||
4375 | if (spec->eapd_mask) | ||
4376 | stac_gpio_set(codec, spec->gpio_mask, | ||
4377 | spec->gpio_dir, spec->gpio_data & | ||
4378 | ~spec->eapd_mask); | ||
4379 | } | ||
4380 | |||
4332 | static void stac92xx_free(struct hda_codec *codec) | 4381 | static void stac92xx_free(struct hda_codec *codec) |
4333 | { | 4382 | { |
4334 | struct sigmatel_spec *spec = codec->spec; | 4383 | struct sigmatel_spec *spec = codec->spec; |
@@ -4336,6 +4385,7 @@ static void stac92xx_free(struct hda_codec *codec) | |||
4336 | if (! spec) | 4385 | if (! spec) |
4337 | return; | 4386 | return; |
4338 | 4387 | ||
4388 | stac92xx_shutup(codec); | ||
4339 | stac92xx_free_jacks(codec); | 4389 | stac92xx_free_jacks(codec); |
4340 | snd_array_free(&spec->events); | 4390 | snd_array_free(&spec->events); |
4341 | 4391 | ||
@@ -4386,12 +4436,16 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, | |||
4386 | pin_ctl & ~flag); | 4436 | pin_ctl & ~flag); |
4387 | } | 4437 | } |
4388 | 4438 | ||
4389 | static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) | 4439 | static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) |
4390 | { | 4440 | { |
4391 | if (!nid) | 4441 | if (!nid) |
4392 | return 0; | 4442 | return 0; |
4393 | if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) | 4443 | /* NOTE: we can't use snd_hda_jack_detect() here because STAC/IDT |
4394 | & (1 << 31)) | 4444 | * codecs behave wrongly when SET_PIN_SENSE is triggered, although |
4445 | * the pincap gives TRIG_REQ bit. | ||
4446 | */ | ||
4447 | if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0) & | ||
4448 | AC_PINSENSE_PRESENCE) | ||
4395 | return 1; | 4449 | return 1; |
4396 | return 0; | 4450 | return 0; |
4397 | } | 4451 | } |
@@ -4791,28 +4845,28 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, | |||
4791 | 4845 | ||
4792 | return 0; | 4846 | return 0; |
4793 | } | 4847 | } |
4794 | #endif | ||
4795 | 4848 | ||
4796 | static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) | 4849 | static int idt92hd83xxx_hp_check_power_status(struct hda_codec *codec, |
4850 | hda_nid_t nid) | ||
4797 | { | 4851 | { |
4798 | struct sigmatel_spec *spec = codec->spec; | 4852 | struct sigmatel_spec *spec = codec->spec; |
4799 | int i; | ||
4800 | hda_nid_t nid; | ||
4801 | 4853 | ||
4802 | /* reset each pin before powering down DAC/ADC to avoid click noise */ | 4854 | if (nid != 0x13) |
4803 | nid = codec->start_nid; | 4855 | return 0; |
4804 | for (i = 0; i < codec->num_nodes; i++, nid++) { | 4856 | if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & HDA_AMP_MUTE) |
4805 | unsigned int wcaps = get_wcaps(codec, nid); | 4857 | spec->gpio_data |= spec->gpio_led; /* mute LED on */ |
4806 | unsigned int wid_type = get_wcaps_type(wcaps); | 4858 | else |
4807 | if (wid_type == AC_WID_PIN) | 4859 | spec->gpio_data &= ~spec->gpio_led; /* mute LED off */ |
4808 | snd_hda_codec_read(codec, nid, 0, | 4860 | stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); |
4809 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
4810 | } | ||
4811 | 4861 | ||
4812 | if (spec->eapd_mask) | 4862 | return 0; |
4813 | stac_gpio_set(codec, spec->gpio_mask, | 4863 | } |
4814 | spec->gpio_dir, spec->gpio_data & | 4864 | |
4815 | ~spec->eapd_mask); | 4865 | #endif |
4866 | |||
4867 | static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) | ||
4868 | { | ||
4869 | stac92xx_shutup(codec); | ||
4816 | return 0; | 4870 | return 0; |
4817 | } | 4871 | } |
4818 | #endif | 4872 | #endif |
@@ -4827,6 +4881,7 @@ static struct hda_codec_ops stac92xx_patch_ops = { | |||
4827 | .suspend = stac92xx_suspend, | 4881 | .suspend = stac92xx_suspend, |
4828 | .resume = stac92xx_resume, | 4882 | .resume = stac92xx_resume, |
4829 | #endif | 4883 | #endif |
4884 | .reboot_notify = stac92xx_shutup, | ||
4830 | }; | 4885 | }; |
4831 | 4886 | ||
4832 | static int patch_stac9200(struct hda_codec *codec) | 4887 | static int patch_stac9200(struct hda_codec *codec) |
@@ -5172,6 +5227,22 @@ again: | |||
5172 | break; | 5227 | break; |
5173 | } | 5228 | } |
5174 | 5229 | ||
5230 | codec->patch_ops = stac92xx_patch_ops; | ||
5231 | |||
5232 | if (spec->board_config == STAC_92HD83XXX_HP) | ||
5233 | spec->gpio_led = 0x01; | ||
5234 | |||
5235 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
5236 | if (spec->gpio_led) { | ||
5237 | spec->gpio_mask |= spec->gpio_led; | ||
5238 | spec->gpio_dir |= spec->gpio_led; | ||
5239 | spec->gpio_data |= spec->gpio_led; | ||
5240 | /* register check_power_status callback. */ | ||
5241 | codec->patch_ops.check_power_status = | ||
5242 | idt92hd83xxx_hp_check_power_status; | ||
5243 | } | ||
5244 | #endif | ||
5245 | |||
5175 | err = stac92xx_parse_auto_config(codec, 0x1d, 0); | 5246 | err = stac92xx_parse_auto_config(codec, 0x1d, 0); |
5176 | if (!err) { | 5247 | if (!err) { |
5177 | if (spec->board_config < 0) { | 5248 | if (spec->board_config < 0) { |
@@ -5207,8 +5278,6 @@ again: | |||
5207 | snd_hda_codec_write_cache(codec, nid, 0, | 5278 | snd_hda_codec_write_cache(codec, nid, 0, |
5208 | AC_VERB_SET_CONNECT_SEL, num_dacs); | 5279 | AC_VERB_SET_CONNECT_SEL, num_dacs); |
5209 | 5280 | ||
5210 | codec->patch_ops = stac92xx_patch_ops; | ||
5211 | |||
5212 | codec->proc_widget_hook = stac92hd_proc_hook; | 5281 | codec->proc_widget_hook = stac92hd_proc_hook; |
5213 | 5282 | ||
5214 | return 0; | 5283 | return 0; |