aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitaliy Kulikov <Vitaliy.Kulikov@idt.com>2011-07-26 17:56:20 -0400
committerTakashi Iwai <tiwai@suse.de>2011-07-27 02:51:10 -0400
commit45eebda7b4a73deb268b0cbcde06b603a2ba46a2 (patch)
tree543bebd6b60156563dbd7c60412d501370937da0
parent636f78581dbd5529a52057973fe2bdfc1c2f528e (diff)
ALSA: hda - Add support for vref-out based mute LED control on IDT codecs
This patch also registers all necessary callbacks to support mute LED only when such control is enabled. And it keeps codec AFG in D0 or D1 state all the time when aggressive power managemnt is enabled for vref-out control (and mute LED) work correctly. Signed-off-by: Vitaliy Kulikov <Vitaliy.Kulikov@idt.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/patch_sigmatel.c199
1 files changed, 156 insertions, 43 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index fcf4c714210..aa376b59c00 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
676static 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
675static unsigned int stac92xx_vref_set(struct hda_codec *codec, 700static 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
4463static 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
4434static void stac92xx_shutup(struct hda_codec *codec) 4478static 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
4938static 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
4949static int stac92xx_resume(struct hda_codec *codec) 4983static 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
5001static 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
5008static 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
5025static 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
5039static 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
5028static 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
5035static const struct hda_codec_ops stac92xx_patch_ops = { 5135static 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 }