ASoC: hdac_hdmi: Add MST verb support
authorJeeja KP <jeeja.kp@intel.com>
Tue, 7 Feb 2017 13:39:45 +0000 (19:09 +0530)
committerMark Brown <broonie@kernel.org>
Thu, 16 Feb 2017 18:55:14 +0000 (18:55 +0000)
To support DP MST audio, new pin verbs/params are added. This patch
adds helper functions to do following:
o To set a specific port
o To get the currently selected port
o To get the length of port.

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Acked-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/hdac_hdmi.c

index 17a1ad3ead2167c303bf03471483bd20d8c7fe66..84b7d6cd7c37ca61f54a8dc6bbecbc041376a5e3 100644 (file)
@@ -142,6 +142,76 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
        return pcm;
 }
 
+/* MST supported verbs */
+/*
+ * Get the no devices that can be connected to a port on the Pin widget.
+ */
+static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid)
+{
+       unsigned int caps;
+       unsigned int type, param;
+
+       caps = get_wcaps(&hdac->hdac, nid);
+       type = get_wcaps_type(caps);
+
+       if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN))
+               return 0;
+
+       param = snd_hdac_read_parm_uncached(&hdac->hdac, nid,
+                                       AC_PAR_DEVLIST_LEN);
+       if (param == -1)
+               return param;
+
+       return param & AC_DEV_LIST_LEN_MASK;
+}
+
+/*
+ * Get the port entry select on the pin. Return the port entry
+ * id selected on the pin. Return 0 means the first port entry
+ * is selected or MST is not supported.
+ */
+static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac,
+                                       struct hdac_hdmi_port *port)
+{
+       return snd_hdac_codec_read(&hdac->hdac, port->pin->nid,
+                               0, AC_VERB_GET_DEVICE_SEL, 0);
+}
+
+/*
+ * Sets the selected port entry for the configuring Pin widget verb.
+ * returns error if port set is not equal to port get otherwise success
+ */
+static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac,
+                                       struct hdac_hdmi_port *port)
+{
+       int num_ports;
+
+       if (!port->pin->mst_capable)
+               return 0;
+
+       /* AC_PAR_DEVLIST_LEN is 0 based. */
+       num_ports = hdac_hdmi_get_port_len(hdac, port->pin->nid);
+
+       if (num_ports < 0)
+               return -EIO;
+       /*
+        * Device List Length is a 0 based integer value indicating the
+        * number of sink device that a MST Pin Widget can support.
+        */
+       if (num_ports + 1  < port->id)
+               return 0;
+
+       snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0,
+                       AC_VERB_SET_DEVICE_SEL, port->id);
+
+       if (port->id != hdac_hdmi_port_select_get(hdac, port))
+               return -EIO;
+
+       dev_dbg(&hdac->hdac.dev, "Selected the port=%d\n", port->id);
+
+       return 0;
+}
+
 static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi,
                                                int pcm_idx)
 {