aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeeja KP <jeeja.kp@intel.com>2017-02-07 08:39:45 -0500
committerMark Brown <broonie@kernel.org>2017-02-16 13:55:14 -0500
commitfc181b04f2d44805624d4bc5a0615bc084199a81 (patch)
tree93799d5818adf927fa5590f4eebc71aa6ab500d8
parent2acd8309a3a4e6dc04e72d2db0716825095c02d6 (diff)
ASoC: hdac_hdmi: Add MST verb support
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>
-rw-r--r--sound/soc/codecs/hdac_hdmi.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 17a1ad3ead21..84b7d6cd7c37 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -142,6 +142,76 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
142 return pcm; 142 return pcm;
143} 143}
144 144
145/* MST supported verbs */
146/*
147 * Get the no devices that can be connected to a port on the Pin widget.
148 */
149static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid)
150{
151 unsigned int caps;
152 unsigned int type, param;
153
154 caps = get_wcaps(&hdac->hdac, nid);
155 type = get_wcaps_type(caps);
156
157 if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN))
158 return 0;
159
160 param = snd_hdac_read_parm_uncached(&hdac->hdac, nid,
161 AC_PAR_DEVLIST_LEN);
162 if (param == -1)
163 return param;
164
165 return param & AC_DEV_LIST_LEN_MASK;
166}
167
168/*
169 * Get the port entry select on the pin. Return the port entry
170 * id selected on the pin. Return 0 means the first port entry
171 * is selected or MST is not supported.
172 */
173static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac,
174 struct hdac_hdmi_port *port)
175{
176 return snd_hdac_codec_read(&hdac->hdac, port->pin->nid,
177 0, AC_VERB_GET_DEVICE_SEL, 0);
178}
179
180/*
181 * Sets the selected port entry for the configuring Pin widget verb.
182 * returns error if port set is not equal to port get otherwise success
183 */
184static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac,
185 struct hdac_hdmi_port *port)
186{
187 int num_ports;
188
189 if (!port->pin->mst_capable)
190 return 0;
191
192 /* AC_PAR_DEVLIST_LEN is 0 based. */
193 num_ports = hdac_hdmi_get_port_len(hdac, port->pin->nid);
194
195 if (num_ports < 0)
196 return -EIO;
197 /*
198 * Device List Length is a 0 based integer value indicating the
199 * number of sink device that a MST Pin Widget can support.
200 */
201 if (num_ports + 1 < port->id)
202 return 0;
203
204 snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0,
205 AC_VERB_SET_DEVICE_SEL, port->id);
206
207 if (port->id != hdac_hdmi_port_select_get(hdac, port))
208 return -EIO;
209
210 dev_dbg(&hdac->hdac.dev, "Selected the port=%d\n", port->id);
211
212 return 0;
213}
214
145static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, 215static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi,
146 int pcm_idx) 216 int pcm_idx)
147{ 217{