]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/pci/hda/hda_codec.c
ALSA: hda: Add HDA vendor ID for Wolfson Microelectronics
[linux-2.6-omap-h63xx.git] / sound / pci / hda / hda_codec.c
index 4f32911508099953a67ad9d8c265b2d2f78e7eda..ba1ab737b55fe44010700aad11a3b316de91e861 100644 (file)
@@ -64,6 +64,7 @@ static struct hda_vendor_id hda_vendor_ids[] = {
        { 0x14f1, "Conexant" },
        { 0x17e8, "Chrontel" },
        { 0x1854, "LG" },
+       { 0x1aec, "Wolfson Microelectronics" },
        { 0x434d, "C-Media" },
        { 0x8384, "SigmaTel" },
        {} /* terminator */
@@ -93,6 +94,9 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
 #endif
 #ifdef CONFIG_SND_HDA_CODEC_VIA
        snd_hda_preset_via,
+#endif
+#ifdef CONFIG_SND_HDA_CODEC_NVHDMI
+       snd_hda_preset_nvhdmi,
 #endif
        NULL
 };
@@ -314,7 +318,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
 }
 
 /*
- * process queueud unsolicited events
+ * process queued unsolicited events
  */
 static void process_unsol_events(struct work_struct *work)
 {
@@ -961,15 +965,6 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
 }
 #endif /* SND_HDA_NEEDS_RESUME */
 
-/*
- * AMP control callbacks
- */
-/* retrieve parameters from private_value */
-#define get_amp_nid(kc)                ((kc)->private_value & 0xffff)
-#define get_amp_channels(kc)   (((kc)->private_value >> 16) & 0x3)
-#define get_amp_direction(kc)  (((kc)->private_value >> 18) & 0x1)
-#define get_amp_index(kc)      (((kc)->private_value >> 19) & 0xf)
-
 /* volume */
 int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
@@ -1435,6 +1430,29 @@ static unsigned int convert_to_spdif_status(unsigned short val)
        return sbits;
 }
 
+/* set digital convert verbs both for the given NID and its slaves */
+static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
+                       int verb, int val)
+{
+       hda_nid_t *d;
+
+       snd_hda_codec_write(codec, nid, 0, verb, val);
+       d = codec->slave_dig_outs;
+       if (!d)
+               return;
+       for (; *d; d++)
+               snd_hda_codec_write(codec, *d, 0, verb, val);
+}
+
+static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid,
+                                      int dig1, int dig2)
+{
+       if (dig1 != -1)
+               set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1);
+       if (dig2 != -1)
+               set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2);
+}
+
 static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
@@ -1453,14 +1471,8 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
        change = codec->spdif_ctls != val;
        codec->spdif_ctls = val;
 
-       if (change) {
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_DIGI_CONVERT_1,
-                                         val & 0xff);
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_DIGI_CONVERT_2,
-                                         val >> 8);
-       }
+       if (change)
+               set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
 
        mutex_unlock(&codec->spdif_mutex);
        return change;
@@ -1492,9 +1504,7 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
        change = codec->spdif_ctls != val;
        if (change) {
                codec->spdif_ctls = val;
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_DIGI_CONVERT_1,
-                                         val & 0xff);
+               set_dig_out_convert(codec, nid, val & 0xff, -1);
                /* unmute amp switch (if any) */
                if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
                    (val & AC_DIG1_ENABLE))
@@ -2591,13 +2601,30 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
 {
        /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
        if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-                                   codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+               set_dig_out_convert(codec, nid, 
+                                   codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
+                                   -1);
        snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+       if (codec->slave_dig_outs) {
+               hda_nid_t *d;
+               for (d = codec->slave_dig_outs; *d; d++)
+                       snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
+                                                  format);
+       }
        /* turn on again (if needed) */
        if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-                                   codec->spdif_ctls & 0xff);
+               set_dig_out_convert(codec, nid,
+                                   codec->spdif_ctls & 0xff, -1);
+}
+
+static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
+{
+       snd_hda_codec_cleanup_stream(codec, nid);
+       if (codec->slave_dig_outs) {
+               hda_nid_t *d;
+               for (d = codec->slave_dig_outs; *d; d++)
+                       snd_hda_codec_cleanup_stream(codec, *d);
+       }
 }
 
 /*
@@ -2609,7 +2636,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec,
        mutex_lock(&codec->spdif_mutex);
        if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
                /* already opened as analog dup; reset it once */
-               snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
+               cleanup_dig_out_stream(codec, mout->dig_out_nid);
        mout->dig_out_used = HDA_DIG_EXCLUSIVE;
        mutex_unlock(&codec->spdif_mutex);
        return 0;
@@ -2704,7 +2731,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
                                             stream_tag, format);
                } else {
                        mout->dig_out_used = 0;
-                       snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
+                       cleanup_dig_out_stream(codec, mout->dig_out_nid);
                }
        }
        mutex_unlock(&codec->spdif_mutex);
@@ -2755,7 +2782,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
                                                     mout->extra_out_nid[i]);
        mutex_lock(&codec->spdif_mutex);
        if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
-               snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
+               cleanup_dig_out_stream(codec, mout->dig_out_nid);
                mout->dig_out_used = 0;
        }
        mutex_unlock(&codec->spdif_mutex);
@@ -2763,7 +2790,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
 }
 
 /*
- * Helper for automatic ping configuration
+ * Helper for automatic pin configuration
  */
 
 static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)