diff options
Diffstat (limited to 'sound/pci/hda/patch_sigmatel.c')
-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 | } |