ALSA: hda - hide HDMI/ELD printks unless snd.debug=2
[linux-2.6.git] / sound / pci / hda / patch_hdmi.c
index a76139b..3e35734 100644 (file)
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
+
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+#include <mach/hdmi-audio.h>
+#endif
+
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_jack.h"
 
 static bool static_hdmi_pcm;
 module_param(static_hdmi_pcm, bool, 0644);
@@ -48,8 +54,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
  *
  * The HDA correspondence of pipes/ports are converter/pin nodes.
  */
-#define MAX_HDMI_CVTS  4
-#define MAX_HDMI_PINS  4
+#define MAX_HDMI_CVTS  8
+#define MAX_HDMI_PINS  8
 
 struct hdmi_spec_per_cvt {
        hda_nid_t cvt_nid;
@@ -69,6 +75,7 @@ struct hdmi_spec_per_pin {
        struct hda_codec *codec;
        struct hdmi_eld sink_eld;
        struct delayed_work work;
+       int repoll_count;
 };
 
 struct hdmi_spec {
@@ -748,35 +755,33 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
  * Unsolicited events
  */
 
-static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry);
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
 
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 {
        struct hdmi_spec *spec = codec->spec;
-       int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT;
-       int pd = !!(res & AC_UNSOL_RES_PD);
-       int eldv = !!(res & AC_UNSOL_RES_ELDV);
+       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+       int pin_nid;
        int pin_idx;
-       struct hdmi_eld *eld;
+       struct hda_jack_tbl *jack;
 
-       printk(KERN_INFO
+       jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
+       if (!jack)
+               return;
+       pin_nid = jack->nid;
+       jack->jack_dirty = 1;
+
+       _snd_printd(SND_PR_VERBOSE,
                "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
-               codec->addr, pin_nid, pd, eldv);
+               codec->addr, pin_nid,
+               !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
 
        pin_idx = pin_nid_to_pin_index(spec, pin_nid);
        if (pin_idx < 0)
                return;
-       eld = &spec->pins[pin_idx].sink_eld;
 
-       hdmi_present_sense(&spec->pins[pin_idx], true);
-
-       /*
-        * HDMI sink's ELD info cannot always be retrieved for now, e.g.
-        * in console or for audio devices. Assume the highest speakers
-        * configuration, to _not_ prohibit multi-channel audio playback.
-        */
-       if (!eld->spk_alloc)
-               eld->spk_alloc = 0xffff;
+       hdmi_present_sense(&spec->pins[pin_idx], 1);
+       snd_hda_jack_report_sync(codec);
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -804,11 +809,10 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
 
 static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       struct hdmi_spec *spec = codec->spec;
        int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
        int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
 
-       if (pin_nid_to_pin_index(spec, tag) < 0) {
+       if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) {
                snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
                return;
        }
@@ -886,6 +890,21 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
        per_pin = &spec->pins[pin_idx];
        eld = &per_pin->sink_eld;
 
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+       if ((codec->preset->id == 0x10de0020) &&
+           (!eld->monitor_present || !eld->lpcm_sad_ready)) {
+               if (!eld->monitor_present) {
+                       if (tegra_hdmi_setup_hda_presence() < 0) {
+                               snd_printk(KERN_WARNING
+                                          "HDMI: No HDMI device connected\n");
+                               return -ENODEV;
+                       }
+               }
+               if (!eld->lpcm_sad_ready)
+                       return -ENODEV;
+       }
+#endif
+
        /* Dynamically assign converter to stream */
        for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
                per_cvt = &spec->cvts[cvt_idx];
@@ -928,7 +947,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
        hinfo->maxbps = per_cvt->maxbps;
 
        /* Restrict capabilities by ELD if this isn't disabled */
-       if (!static_hdmi_pcm && eld->eld_valid) {
+       if (!static_hdmi_pcm && (eld->eld_valid || eld->lpcm_sad_ready)) {
                snd_hdmi_eld_update_pcm_info(eld, hinfo);
                if (hinfo->channels_min > hinfo->channels_max ||
                    !hinfo->rates || !hinfo->formats)
@@ -970,7 +989,7 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
        return 0;
 }
 
-static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry)
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
 {
        struct hda_codec *codec = per_pin->codec;
        struct hdmi_eld *eld = &per_pin->sink_eld;
@@ -992,21 +1011,19 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry)
        if (eld->monitor_present)
                eld_valid       = !!(present & AC_PINSENSE_ELDV);
 
-       printk(KERN_INFO
+       _snd_printd(SND_PR_VERBOSE,
                "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
                codec->addr, pin_nid, eld->monitor_present, eld_valid);
 
        if (eld_valid) {
                if (!snd_hdmi_get_eld(eld, codec, pin_nid))
                        snd_hdmi_show_eld(eld);
-               else if (retry) {
+               else if (repoll) {
                        queue_delayed_work(codec->bus->workq,
                                           &per_pin->work,
                                           msecs_to_jiffies(300));
                }
        }
-
-       snd_hda_input_jack_report(codec, pin_nid);
 }
 
 static void hdmi_repoll_eld(struct work_struct *work)
@@ -1014,7 +1031,10 @@ static void hdmi_repoll_eld(struct work_struct *work)
        struct hdmi_spec_per_pin *per_pin =
        container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
 
-       hdmi_present_sense(per_pin, false);
+       if (per_pin->repoll_count++ > 6)
+               per_pin->repoll_count = 0;
+
+       hdmi_present_sense(per_pin, per_pin->repoll_count);
 }
 
 static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
@@ -1122,8 +1142,8 @@ static int hdmi_parse_codec(struct hda_codec *codec)
         * HDA link is powered off at hot plug or hw initialization time.
         */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
-             AC_PWRST_EPSS))
+       if ((!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
+             AC_PWRST_EPSS)) && (codec->preset->id != 0x10de0020))
                codec->bus->power_keep_link_on = 1;
 #endif
 
@@ -1132,12 +1152,12 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
 /*
  */
-static char *generic_hdmi_pcm_names[MAX_HDMI_PINS] = {
-       "HDMI 0",
-       "HDMI 1",
-       "HDMI 2",
-       "HDMI 3",
-};
+static char *get_hdmi_pcm_name(int idx)
+{
+       static char names[MAX_HDMI_PINS][8];
+       sprintf(&names[idx][0], "HDMI %d", idx);
+       return &names[idx][0];
+}
 
 /*
  * HDMI callbacks
@@ -1154,6 +1174,21 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        int pin_idx = hinfo_to_pin_index(spec, hinfo);
        hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
 
+#if defined(CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA) && defined(CONFIG_TEGRA_DC)
+       if (codec->preset->id == 0x10de0020) {
+               int err = 0;
+               /* Set hdmi:audio freq and source selection*/
+               err = tegra_hdmi_setup_audio_freq_source(
+                                       substream->runtime->rate, HDA);
+               if ( err < 0 ) {
+                       snd_printk(KERN_ERR
+                               "Unable to set hdmi audio freq to %d \n",
+                                               substream->runtime->rate);
+                       return err;
+               }
+       }
+#endif
+
        hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
 
        hdmi_setup_audio_infoframe(codec, pin_idx, substream);
@@ -1215,7 +1250,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
                struct hda_pcm_stream *pstr;
 
                info = &spec->pcm_rec[pin_idx];
-               info->name = generic_hdmi_pcm_names[pin_idx];
+               info->name = get_hdmi_pcm_name(pin_idx);
                info->pcm_type = HDA_PCM_TYPE_HDMI;
 
                pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
@@ -1232,21 +1267,15 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
 
 static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
 {
-       int err;
-       char hdmi_str[32];
+       char hdmi_str[32] = "HDMI/DP";
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
        int pcmdev = spec->pcm_rec[pin_idx].device;
 
-       snprintf(hdmi_str, sizeof(hdmi_str), "HDMI/DP,pcm=%d", pcmdev);
+       if (pcmdev > 0)
+               sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
 
-       err = snd_hda_input_jack_add(codec, per_pin->pin_nid,
-                            SND_JACK_VIDEOOUT, pcmdev > 0 ? hdmi_str : NULL);
-       if (err < 0)
-               return err;
-
-       hdmi_present_sense(per_pin, false);
-       return 0;
+       return snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str, 0);
 }
 
 static int generic_hdmi_build_controls(struct hda_codec *codec)
@@ -1276,6 +1305,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 
                if (err < 0)
                        return err;
+
+               hdmi_present_sense(per_pin, 0);
        }
 
        return 0;
@@ -1286,20 +1317,27 @@ static int generic_hdmi_init(struct hda_codec *codec)
        struct hdmi_spec *spec = codec->spec;
        int pin_idx;
 
+       switch (codec->preset->id) {
+       case 0x10de0020:
+               snd_hda_codec_write(codec, 4, 0,
+                                   AC_VERB_SET_DIGI_CONVERT_1, 0x11);
+       default:
+               break;
+       }
+
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
                struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
                hda_nid_t pin_nid = per_pin->pin_nid;
                struct hdmi_eld *eld = &per_pin->sink_eld;
 
                hdmi_init_pin(codec, pin_nid);
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                   AC_VERB_SET_UNSOLICITED_ENABLE,
-                                   AC_USRSP_EN | pin_nid);
+               snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
 
                per_pin->codec = codec;
                INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
                snd_hda_eld_proc_new(codec, eld, pin_idx);
        }
+       snd_hda_jack_report_sync(codec);
        return 0;
 }
 
@@ -1315,7 +1353,6 @@ static void generic_hdmi_free(struct hda_codec *codec)
                cancel_delayed_work(&per_pin->work);
                snd_hda_eld_proc_free(codec, eld);
        }
-       snd_hda_input_jack_free(codec);
 
        flush_workqueue(codec->bus->workq);
        kfree(spec);
@@ -1370,7 +1407,7 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
                chans = get_wcaps(codec, spec->cvts[i].cvt_nid);
                chans = get_wcaps_channels(chans);
 
-               info->name = generic_hdmi_pcm_names[i];
+               info->name = get_hdmi_pcm_name(i);
                info->pcm_type = HDA_PCM_TYPE_HDMI;
                pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
                snd_BUG_ON(!spec->pcm_playback);
@@ -1903,6 +1940,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x10de001a, .name = "GPU 1a HDMI/DP",  .patch = patch_generic_hdmi },
 { .id = 0x10de001b, .name = "GPU 1b HDMI/DP",  .patch = patch_generic_hdmi },
 { .id = 0x10de001c, .name = "GPU 1c HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0020, .name = "Tegra30 HDMI",    .patch = patch_generic_hdmi },
 { .id = 0x10de0040, .name = "GPU 40 HDMI/DP",  .patch = patch_generic_hdmi },
 { .id = 0x10de0041, .name = "GPU 41 HDMI/DP",  .patch = patch_generic_hdmi },
 { .id = 0x10de0042, .name = "GPU 42 HDMI/DP",  .patch = patch_generic_hdmi },
@@ -1917,6 +1955,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x80862804, .name = "IbexPeak HDMI",   .patch = patch_generic_hdmi },
 { .id = 0x80862805, .name = "CougarPoint HDMI",        .patch = patch_generic_hdmi },
 { .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi },
 { .id = 0x808629fb, .name = "Crestline HDMI",  .patch = patch_generic_hdmi },
 {} /* terminator */
 };
@@ -1948,6 +1987,7 @@ MODULE_ALIAS("snd-hda-codec-id:10de0019");
 MODULE_ALIAS("snd-hda-codec-id:10de001a");
 MODULE_ALIAS("snd-hda-codec-id:10de001b");
 MODULE_ALIAS("snd-hda-codec-id:10de001c");
+MODULE_ALIAS("snd-hda-codec-id:10de0020");
 MODULE_ALIAS("snd-hda-codec-id:10de0040");
 MODULE_ALIAS("snd-hda-codec-id:10de0041");
 MODULE_ALIAS("snd-hda-codec-id:10de0042");
@@ -1963,6 +2003,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862803");
 MODULE_ALIAS("snd-hda-codec-id:80862804");
 MODULE_ALIAS("snd-hda-codec-id:80862805");
 MODULE_ALIAS("snd-hda-codec-id:80862806");
+MODULE_ALIAS("snd-hda-codec-id:80862880");
 MODULE_ALIAS("snd-hda-codec-id:808629fb");
 
 MODULE_LICENSE("GPL");