diff options
| -rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 199 |
1 files changed, 156 insertions, 43 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index fcf4c7142103..aa376b59c006 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
| @@ -213,6 +213,7 @@ struct sigmatel_spec { | |||
| 213 | unsigned int gpio_mute; | 213 | unsigned int gpio_mute; |
| 214 | unsigned int gpio_led; | 214 | unsigned int gpio_led; |
| 215 | unsigned int gpio_led_polarity; | 215 | unsigned int gpio_led_polarity; |
| 216 | unsigned int vref_led; | ||
| 216 | 217 | ||
| 217 | /* stream */ | 218 | /* stream */ |
| 218 | unsigned int stream_delay; | 219 | unsigned int stream_delay; |
| @@ -672,6 +673,30 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, | |||
| 672 | return 0; | 673 | return 0; |
| 673 | } | 674 | } |
| 674 | 675 | ||
| 676 | static int stac_vrefout_set(struct hda_codec *codec, | ||
| 677 | hda_nid_t nid, unsigned int new_vref) | ||
| 678 | { | ||
| 679 | int error, pinctl; | ||
| 680 | |||
| 681 | snd_printdd("%s, nid %x ctl %x\n", __func__, nid, new_vref); | ||
| 682 | pinctl = snd_hda_codec_read(codec, nid, 0, | ||
| 683 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
| 684 | |||
| 685 | if (pinctl < 0) | ||
| 686 | return pinctl; | ||
| 687 | |||
| 688 | pinctl &= 0xff; | ||
| 689 | pinctl &= ~AC_PINCTL_VREFEN; | ||
| 690 | pinctl |= (new_vref & AC_PINCTL_VREFEN); | ||
| 691 | |||
| 692 | error = snd_hda_codec_write_cache(codec, nid, 0, | ||
| 693 | AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); | ||
| 694 | if (error < 0) | ||
| 695 | return error; | ||
| 696 | |||
| 697 | return 1; | ||
| 698 | } | ||
| 699 | |||
| 675 | static unsigned int stac92xx_vref_set(struct hda_codec *codec, | 700 | static unsigned int stac92xx_vref_set(struct hda_codec *codec, |
| 676 | hda_nid_t nid, unsigned int new_vref) | 701 | hda_nid_t nid, unsigned int new_vref) |
| 677 | { | 702 | { |
| @@ -4069,6 +4094,8 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, | |||
| 4069 | { | 4094 | { |
| 4070 | unsigned int gpiostate, gpiomask, gpiodir; | 4095 | unsigned int gpiostate, gpiomask, gpiodir; |
| 4071 | 4096 | ||
| 4097 | snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data); | ||
| 4098 | |||
| 4072 | gpiostate = snd_hda_codec_read(codec, codec->afg, 0, | 4099 | gpiostate = snd_hda_codec_read(codec, codec->afg, 0, |
| 4073 | AC_VERB_GET_GPIO_DATA, 0); | 4100 | AC_VERB_GET_GPIO_DATA, 0); |
| 4074 | gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask); | 4101 | gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask); |
| @@ -4258,10 +4285,12 @@ static void stac_store_hints(struct hda_codec *codec) | |||
| 4258 | spec->eapd_switch = val; | 4285 | spec->eapd_switch = val; |
| 4259 | get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity); | 4286 | get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity); |
| 4260 | if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { | 4287 | if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { |
| 4261 | spec->gpio_mask |= spec->gpio_led; | 4288 | if (spec->gpio_led <= 8) { |
| 4262 | spec->gpio_dir |= spec->gpio_led; | 4289 | spec->gpio_mask |= spec->gpio_led; |
| 4263 | if (spec->gpio_led_polarity) | 4290 | spec->gpio_dir |= spec->gpio_led; |
| 4264 | spec->gpio_data |= spec->gpio_led; | 4291 | if (spec->gpio_led_polarity) |
| 4292 | spec->gpio_data |= spec->gpio_led; | ||
| 4293 | } | ||
| 4265 | } | 4294 | } |
| 4266 | } | 4295 | } |
| 4267 | 4296 | ||
| @@ -4431,11 +4460,26 @@ static void stac92xx_free_kctls(struct hda_codec *codec) | |||
| 4431 | snd_array_free(&spec->kctls); | 4460 | snd_array_free(&spec->kctls); |
| 4432 | } | 4461 | } |
| 4433 | 4462 | ||
| 4463 | static void stac92xx_shutup_pins(struct hda_codec *codec) | ||
| 4464 | { | ||
| 4465 | unsigned int i, def_conf; | ||
| 4466 | |||
| 4467 | if (codec->bus->shutdown) | ||
| 4468 | return; | ||
| 4469 | for (i = 0; i < codec->init_pins.used; i++) { | ||
| 4470 | struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); | ||
| 4471 | def_conf = snd_hda_codec_get_pincfg(codec, pin->nid); | ||
| 4472 | if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) | ||
| 4473 | snd_hda_codec_write(codec, pin->nid, 0, | ||
| 4474 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
| 4475 | } | ||
| 4476 | } | ||
| 4477 | |||
| 4434 | static void stac92xx_shutup(struct hda_codec *codec) | 4478 | static void stac92xx_shutup(struct hda_codec *codec) |
| 4435 | { | 4479 | { |
| 4436 | struct sigmatel_spec *spec = codec->spec; | 4480 | struct sigmatel_spec *spec = codec->spec; |
| 4437 | 4481 | ||
| 4438 | snd_hda_shutup_pins(codec); | 4482 | stac92xx_shutup_pins(codec); |
| 4439 | 4483 | ||
| 4440 | if (spec->eapd_mask) | 4484 | if (spec->eapd_mask) |
| 4441 | stac_gpio_set(codec, spec->gpio_mask, | 4485 | stac_gpio_set(codec, spec->gpio_mask, |
| @@ -4833,10 +4877,11 @@ static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity) | |||
| 4833 | if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) { | 4877 | if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) { |
| 4834 | while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, | 4878 | while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, |
| 4835 | NULL, dev))) { | 4879 | NULL, dev))) { |
| 4836 | if (sscanf(dev->name, "HP_Mute_LED_%d_%d", | 4880 | if (sscanf(dev->name, "HP_Mute_LED_%d_%x", |
| 4837 | &spec->gpio_led_polarity, | 4881 | &spec->gpio_led_polarity, |
| 4838 | &spec->gpio_led) == 2) { | 4882 | &spec->gpio_led) == 2) { |
| 4839 | spec->gpio_led = 1 << spec->gpio_led; | 4883 | if (spec->gpio_led < 4) |
| 4884 | spec->gpio_led = 1 << spec->gpio_led; | ||
| 4840 | return 1; | 4885 | return 1; |
| 4841 | } | 4886 | } |
| 4842 | if (sscanf(dev->name, "HP_Mute_LED_%d", | 4887 | if (sscanf(dev->name, "HP_Mute_LED_%d", |
| @@ -4935,17 +4980,6 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer, | |||
| 4935 | #endif | 4980 | #endif |
| 4936 | 4981 | ||
| 4937 | #ifdef CONFIG_PM | 4982 | #ifdef CONFIG_PM |
| 4938 | static int stac92xx_pre_resume(struct hda_codec *codec) | ||
| 4939 | { | ||
| 4940 | struct sigmatel_spec *spec = codec->spec; | ||
| 4941 | |||
| 4942 | /* sync mute LED */ | ||
| 4943 | if (spec->gpio_led) | ||
| 4944 | stac_gpio_set(codec, spec->gpio_mask, | ||
| 4945 | spec->gpio_dir, spec->gpio_data); | ||
| 4946 | return 0; | ||
| 4947 | } | ||
| 4948 | |||
| 4949 | static int stac92xx_resume(struct hda_codec *codec) | 4983 | static int stac92xx_resume(struct hda_codec *codec) |
| 4950 | { | 4984 | { |
| 4951 | struct sigmatel_spec *spec = codec->spec; | 4985 | struct sigmatel_spec *spec = codec->spec; |
| @@ -4964,7 +4998,65 @@ static int stac92xx_resume(struct hda_codec *codec) | |||
| 4964 | return 0; | 4998 | return 0; |
| 4965 | } | 4999 | } |
| 4966 | 5000 | ||
| 5001 | static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) | ||
| 5002 | { | ||
| 5003 | stac92xx_shutup(codec); | ||
| 5004 | return 0; | ||
| 5005 | } | ||
| 5006 | |||
| 4967 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 5007 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 5008 | static int stac92xx_pre_resume(struct hda_codec *codec) | ||
| 5009 | { | ||
| 5010 | struct sigmatel_spec *spec = codec->spec; | ||
| 5011 | |||
| 5012 | /* sync mute LED */ | ||
| 5013 | if (spec->gpio_led) { | ||
| 5014 | if (spec->gpio_led <= 8) { | ||
| 5015 | stac_gpio_set(codec, spec->gpio_mask, | ||
| 5016 | spec->gpio_dir, spec->gpio_data); | ||
| 5017 | } else { | ||
| 5018 | stac_vrefout_set(codec, | ||
| 5019 | spec->gpio_led, spec->vref_led); | ||
| 5020 | } | ||
| 5021 | } | ||
| 5022 | return 0; | ||
| 5023 | } | ||
| 5024 | |||
| 5025 | static int stac92xx_post_suspend(struct hda_codec *codec) | ||
| 5026 | { | ||
| 5027 | struct sigmatel_spec *spec = codec->spec; | ||
| 5028 | if (spec->gpio_led > 8) { | ||
| 5029 | /* with vref-out pin used for mute led control | ||
| 5030 | * codec AFG is prevented from D3 state, but on | ||
| 5031 | * system suspend it can (and should) be used | ||
| 5032 | */ | ||
| 5033 | snd_hda_codec_read(codec, codec->afg, 0, | ||
| 5034 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
| 5035 | } | ||
| 5036 | return 0; | ||
| 5037 | } | ||
| 5038 | |||
| 5039 | static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||
| 5040 | unsigned int power_state) | ||
| 5041 | { | ||
| 5042 | unsigned int afg_power_state = power_state; | ||
| 5043 | struct sigmatel_spec *spec = codec->spec; | ||
| 5044 | |||
| 5045 | if (power_state == AC_PWRST_D3) { | ||
| 5046 | if (spec->gpio_led > 8) { | ||
| 5047 | /* with vref-out pin used for mute led control | ||
| 5048 | * codec AFG is prevented from D3 state | ||
| 5049 | */ | ||
| 5050 | afg_power_state = AC_PWRST_D1; | ||
| 5051 | } | ||
| 5052 | /* this delay seems necessary to avoid click noise at power-down */ | ||
| 5053 | msleep(100); | ||
| 5054 | } | ||
| 5055 | snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, | ||
| 5056 | afg_power_state); | ||
| 5057 | snd_hda_codec_set_power_to_all(codec, fg, power_state, true); | ||
| 5058 | } | ||
| 5059 | |||
| 4968 | /* | 5060 | /* |
| 4969 | * For this feature CONFIG_SND_HDA_POWER_SAVE is needed | 5061 | * For this feature CONFIG_SND_HDA_POWER_SAVE is needed |
| 4970 | * as mute LED state is updated in check_power_status hook | 5062 | * as mute LED state is updated in check_power_status hook |
| @@ -4973,8 +5065,12 @@ static int stac92xx_update_led_status(struct hda_codec *codec) | |||
| 4973 | { | 5065 | { |
| 4974 | struct sigmatel_spec *spec = codec->spec; | 5066 | struct sigmatel_spec *spec = codec->spec; |
| 4975 | int i, num_ext_dacs, muted = 1; | 5067 | int i, num_ext_dacs, muted = 1; |
| 5068 | unsigned int muted_lvl, notmtd_lvl; | ||
| 4976 | hda_nid_t nid; | 5069 | hda_nid_t nid; |
| 4977 | 5070 | ||
| 5071 | if (!spec->gpio_led) | ||
| 5072 | return 0; | ||
| 5073 | |||
| 4978 | for (i = 0; i < spec->multiout.num_dacs; i++) { | 5074 | for (i = 0; i < spec->multiout.num_dacs; i++) { |
| 4979 | nid = spec->multiout.dac_nids[i]; | 5075 | nid = spec->multiout.dac_nids[i]; |
| 4980 | if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & | 5076 | if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & |
| @@ -4999,17 +5095,27 @@ static int stac92xx_update_led_status(struct hda_codec *codec) | |||
| 4999 | muted = 0; /* extra output is not muted */ | 5095 | muted = 0; /* extra output is not muted */ |
| 5000 | } | 5096 | } |
| 5001 | } | 5097 | } |
| 5002 | if (muted) | 5098 | /*polarity defines *not* muted state level*/ |
| 5003 | spec->gpio_data &= ~spec->gpio_led; /* orange */ | 5099 | if (spec->gpio_led <= 8) { |
| 5004 | else | 5100 | if (muted) |
| 5005 | spec->gpio_data |= spec->gpio_led; /* white */ | 5101 | spec->gpio_data &= ~spec->gpio_led; /* orange */ |
| 5102 | else | ||
| 5103 | spec->gpio_data |= spec->gpio_led; /* white */ | ||
| 5006 | 5104 | ||
| 5007 | if (!spec->gpio_led_polarity) { | 5105 | if (!spec->gpio_led_polarity) { |
| 5008 | /* LED state is inverted on these systems */ | 5106 | /* LED state is inverted on these systems */ |
| 5009 | spec->gpio_data ^= spec->gpio_led; | 5107 | spec->gpio_data ^= spec->gpio_led; |
| 5108 | } | ||
| 5109 | stac_gpio_set(codec, spec->gpio_mask, | ||
| 5110 | spec->gpio_dir, spec->gpio_data); | ||
| 5111 | } else { | ||
| 5112 | notmtd_lvl = spec->gpio_led_polarity ? | ||
| 5113 | AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_GRD; | ||
| 5114 | muted_lvl = spec->gpio_led_polarity ? | ||
| 5115 | AC_PINCTL_VREF_GRD : AC_PINCTL_VREF_HIZ; | ||
| 5116 | spec->vref_led = muted ? muted_lvl : notmtd_lvl; | ||
| 5117 | stac_vrefout_set(codec, spec->gpio_led, spec->vref_led); | ||
| 5010 | } | 5118 | } |
| 5011 | |||
| 5012 | stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); | ||
| 5013 | return 0; | 5119 | return 0; |
| 5014 | } | 5120 | } |
| 5015 | 5121 | ||
| @@ -5023,13 +5129,7 @@ static int stac92xx_check_power_status(struct hda_codec *codec, | |||
| 5023 | 5129 | ||
| 5024 | return 0; | 5130 | return 0; |
| 5025 | } | 5131 | } |
| 5026 | #endif | 5132 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ |
| 5027 | |||
| 5028 | static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) | ||
| 5029 | { | ||
| 5030 | stac92xx_shutup(codec); | ||
| 5031 | return 0; | ||
| 5032 | } | ||
| 5033 | #endif /* CONFIG_PM */ | 5133 | #endif /* CONFIG_PM */ |
| 5034 | 5134 | ||
| 5035 | static const struct hda_codec_ops stac92xx_patch_ops = { | 5135 | static const struct hda_codec_ops stac92xx_patch_ops = { |
| @@ -5041,7 +5141,6 @@ static const struct hda_codec_ops stac92xx_patch_ops = { | |||
| 5041 | #ifdef CONFIG_PM | 5141 | #ifdef CONFIG_PM |
| 5042 | .suspend = stac92xx_suspend, | 5142 | .suspend = stac92xx_suspend, |
| 5043 | .resume = stac92xx_resume, | 5143 | .resume = stac92xx_resume, |
| 5044 | .pre_resume = stac92xx_pre_resume, | ||
| 5045 | #endif | 5144 | #endif |
| 5046 | .reboot_notify = stac92xx_shutup, | 5145 | .reboot_notify = stac92xx_shutup, |
| 5047 | }; | 5146 | }; |
| @@ -5555,10 +5654,17 @@ again: | |||
| 5555 | 5654 | ||
| 5556 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 5655 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 5557 | if (spec->gpio_led) { | 5656 | if (spec->gpio_led) { |
| 5558 | spec->gpio_mask |= spec->gpio_led; | 5657 | if (spec->gpio_led <= 8) { |
| 5559 | spec->gpio_dir |= spec->gpio_led; | 5658 | spec->gpio_mask |= spec->gpio_led; |
| 5560 | spec->gpio_data |= spec->gpio_led; | 5659 | spec->gpio_dir |= spec->gpio_led; |
| 5561 | /* register check_power_status callback. */ | 5660 | spec->gpio_data |= spec->gpio_led; |
| 5661 | } else { | ||
| 5662 | codec->patch_ops.set_power_state = | ||
| 5663 | stac92xx_set_power_state; | ||
| 5664 | codec->patch_ops.post_suspend = | ||
| 5665 | stac92xx_post_suspend; | ||
| 5666 | } | ||
| 5667 | codec->patch_ops.pre_resume = stac92xx_pre_resume; | ||
| 5562 | codec->patch_ops.check_power_status = | 5668 | codec->patch_ops.check_power_status = |
| 5563 | stac92xx_check_power_status; | 5669 | stac92xx_check_power_status; |
| 5564 | } | 5670 | } |
| @@ -5883,10 +5989,17 @@ again: | |||
| 5883 | 5989 | ||
| 5884 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 5990 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 5885 | if (spec->gpio_led) { | 5991 | if (spec->gpio_led) { |
| 5886 | spec->gpio_mask |= spec->gpio_led; | 5992 | if (spec->gpio_led <= 8) { |
| 5887 | spec->gpio_dir |= spec->gpio_led; | 5993 | spec->gpio_mask |= spec->gpio_led; |
| 5888 | spec->gpio_data |= spec->gpio_led; | 5994 | spec->gpio_dir |= spec->gpio_led; |
| 5889 | /* register check_power_status callback. */ | 5995 | spec->gpio_data |= spec->gpio_led; |
| 5996 | } else { | ||
| 5997 | codec->patch_ops.set_power_state = | ||
| 5998 | stac92xx_set_power_state; | ||
| 5999 | codec->patch_ops.post_suspend = | ||
| 6000 | stac92xx_post_suspend; | ||
| 6001 | } | ||
| 6002 | codec->patch_ops.pre_resume = stac92xx_pre_resume; | ||
| 5890 | codec->patch_ops.check_power_status = | 6003 | codec->patch_ops.check_power_status = |
| 5891 | stac92xx_check_power_status; | 6004 | stac92xx_check_power_status; |
| 5892 | } | 6005 | } |
