xref: /openbmc/linux/sound/soc/codecs/hdac_hdmi.c (revision f6fa11a3)
118382eadSSubhransu S. Prusty /*
218382eadSSubhransu S. Prusty  *  hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms
318382eadSSubhransu S. Prusty  *
418382eadSSubhransu S. Prusty  *  Copyright (C) 2014-2015 Intel Corp
518382eadSSubhransu S. Prusty  *  Author: Samreen Nilofer <samreen.nilofer@intel.com>
618382eadSSubhransu S. Prusty  *	    Subhransu S. Prusty <subhransu.s.prusty@intel.com>
718382eadSSubhransu S. Prusty  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
818382eadSSubhransu S. Prusty  *
918382eadSSubhransu S. Prusty  *  This program is free software; you can redistribute it and/or modify
1018382eadSSubhransu S. Prusty  *  it under the terms of the GNU General Public License as published by
1118382eadSSubhransu S. Prusty  *  the Free Software Foundation; version 2 of the License.
1218382eadSSubhransu S. Prusty  *
1318382eadSSubhransu S. Prusty  *  This program is distributed in the hope that it will be useful, but
1418382eadSSubhransu S. Prusty  *  WITHOUT ANY WARRANTY; without even the implied warranty of
1518382eadSSubhransu S. Prusty  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1618382eadSSubhransu S. Prusty  *  General Public License for more details.
1718382eadSSubhransu S. Prusty  *
1818382eadSSubhransu S. Prusty  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1918382eadSSubhransu S. Prusty  */
2018382eadSSubhransu S. Prusty #include <linux/init.h>
2118382eadSSubhransu S. Prusty #include <linux/delay.h>
2218382eadSSubhransu S. Prusty #include <linux/module.h>
2318382eadSSubhransu S. Prusty #include <linux/pm_runtime.h>
24a657f1d0SSubhransu S. Prusty #include <linux/hdmi.h>
252428bca3SSubhransu S. Prusty #include <drm/drm_edid.h>
2618382eadSSubhransu S. Prusty #include <sound/pcm_params.h>
274a3478deSJeeja KP #include <sound/jack.h>
2818382eadSSubhransu S. Prusty #include <sound/soc.h>
2918382eadSSubhransu S. Prusty #include <sound/hdaudio_ext.h>
3007f083abSSubhransu S. Prusty #include <sound/hda_i915.h>
312428bca3SSubhransu S. Prusty #include <sound/pcm_drm_eld.h>
32bcced704SSubhransu S. Prusty #include <sound/hda_chmap.h>
3318382eadSSubhransu S. Prusty #include "../../hda/local.h"
344a3478deSJeeja KP #include "hdac_hdmi.h"
3518382eadSSubhransu S. Prusty 
3617a42c45SSubhransu S. Prusty #define NAME_SIZE	32
3717a42c45SSubhransu S. Prusty 
38b0362adbSSubhransu S. Prusty #define AMP_OUT_MUTE		0xb080
39b0362adbSSubhransu S. Prusty #define AMP_OUT_UNMUTE		0xb000
4018382eadSSubhransu S. Prusty #define PIN_OUT			(AC_PINCTL_OUT_EN)
41b0362adbSSubhransu S. Prusty 
4218382eadSSubhransu S. Prusty #define HDA_MAX_CONNECTIONS     32
4318382eadSSubhransu S. Prusty 
44148569fdSSubhransu S. Prusty #define HDA_MAX_CVTS		3
45148569fdSSubhransu S. Prusty 
46b8a54545SSubhransu S. Prusty #define ELD_MAX_SIZE    256
47b8a54545SSubhransu S. Prusty #define ELD_FIXED_BYTES	20
48b8a54545SSubhransu S. Prusty 
49f6fa11a3SSandeep Tayal #define ELD_VER_CEA_861D 2
50f6fa11a3SSandeep Tayal #define ELD_VER_PARTIAL 31
51f6fa11a3SSandeep Tayal #define ELD_MAX_MNL     16
52f6fa11a3SSandeep Tayal 
5318382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params {
5418382eadSSubhransu S. Prusty 	unsigned int channels_min;
5518382eadSSubhransu S. Prusty 	unsigned int channels_max;
5618382eadSSubhransu S. Prusty 	u32 rates;
5718382eadSSubhransu S. Prusty 	u64 formats;
5818382eadSSubhransu S. Prusty 	unsigned int maxbps;
5918382eadSSubhransu S. Prusty };
6018382eadSSubhransu S. Prusty 
6118382eadSSubhransu S. Prusty struct hdac_hdmi_cvt {
6215b91447SSubhransu S. Prusty 	struct list_head head;
6318382eadSSubhransu S. Prusty 	hda_nid_t nid;
644a3478deSJeeja KP 	const char *name;
6518382eadSSubhransu S. Prusty 	struct hdac_hdmi_cvt_params params;
6618382eadSSubhransu S. Prusty };
6718382eadSSubhransu S. Prusty 
68b7756edeSSubhransu S. Prusty /* Currently only spk_alloc, more to be added */
69b7756edeSSubhransu S. Prusty struct hdac_hdmi_parsed_eld {
70b7756edeSSubhransu S. Prusty 	u8 spk_alloc;
71b7756edeSSubhransu S. Prusty };
72b7756edeSSubhransu S. Prusty 
73b8a54545SSubhransu S. Prusty struct hdac_hdmi_eld {
74b8a54545SSubhransu S. Prusty 	bool	monitor_present;
75b8a54545SSubhransu S. Prusty 	bool	eld_valid;
76b8a54545SSubhransu S. Prusty 	int	eld_size;
77b8a54545SSubhransu S. Prusty 	char    eld_buffer[ELD_MAX_SIZE];
78b7756edeSSubhransu S. Prusty 	struct	hdac_hdmi_parsed_eld info;
79b8a54545SSubhransu S. Prusty };
80b8a54545SSubhransu S. Prusty 
8118382eadSSubhransu S. Prusty struct hdac_hdmi_pin {
8215b91447SSubhransu S. Prusty 	struct list_head head;
8318382eadSSubhransu S. Prusty 	hda_nid_t nid;
8418382eadSSubhransu S. Prusty 	int num_mux_nids;
8518382eadSSubhransu S. Prusty 	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
86b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_eld eld;
87b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev;
88bcced704SSubhransu S. Prusty 	struct mutex lock;
89bcced704SSubhransu S. Prusty 	bool chmap_set;
90bcced704SSubhransu S. Prusty 	unsigned char chmap[8]; /* ALSA API channel-map */
91bcced704SSubhransu S. Prusty 	int channels; /* current number of channels */
9218382eadSSubhransu S. Prusty };
9318382eadSSubhransu S. Prusty 
944a3478deSJeeja KP struct hdac_hdmi_pcm {
954a3478deSJeeja KP 	struct list_head head;
964a3478deSJeeja KP 	int pcm_id;
974a3478deSJeeja KP 	struct hdac_hdmi_pin *pin;
984a3478deSJeeja KP 	struct hdac_hdmi_cvt *cvt;
994a3478deSJeeja KP 	struct snd_jack *jack;
1004a3478deSJeeja KP };
1014a3478deSJeeja KP 
10218382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map {
10318382eadSSubhransu S. Prusty 	int dai_id;
10415b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
10515b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
10618382eadSSubhransu S. Prusty };
10718382eadSSubhransu S. Prusty 
10818382eadSSubhransu S. Prusty struct hdac_hdmi_priv {
109148569fdSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS];
11015b91447SSubhransu S. Prusty 	struct list_head pin_list;
11115b91447SSubhransu S. Prusty 	struct list_head cvt_list;
1124a3478deSJeeja KP 	struct list_head pcm_list;
11315b91447SSubhransu S. Prusty 	int num_pin;
11415b91447SSubhransu S. Prusty 	int num_cvt;
1154a3478deSJeeja KP 	struct mutex pin_mutex;
116bcced704SSubhransu S. Prusty 	struct hdac_chmap chmap;
11718382eadSSubhransu S. Prusty };
11818382eadSSubhransu S. Prusty 
1191de777feSJeeja KP static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev,
1201de777feSJeeja KP 			struct hdac_hdmi_dai_pin_map *dai_map);
1211de777feSJeeja KP 
1221de777feSJeeja KP static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac,
1231de777feSJeeja KP 			struct hdac_hdmi_dai_pin_map *dai_map);
1241de777feSJeeja KP 
1252889099eSSubhransu S. Prusty static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi,
1262889099eSSubhransu S. Prusty 						int pcm_idx)
1272889099eSSubhransu S. Prusty {
1282889099eSSubhransu S. Prusty 	struct hdac_hdmi_pcm *pcm;
1292889099eSSubhransu S. Prusty 
1302889099eSSubhransu S. Prusty 	list_for_each_entry(pcm, &hdmi->pcm_list, head) {
1312889099eSSubhransu S. Prusty 		if (pcm->pcm_id == pcm_idx)
1322889099eSSubhransu S. Prusty 			return pcm;
1332889099eSSubhransu S. Prusty 	}
1342889099eSSubhransu S. Prusty 
1352889099eSSubhransu S. Prusty 	return NULL;
1362889099eSSubhransu S. Prusty }
1372889099eSSubhransu S. Prusty 
138e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
139e342ac08SSubhransu S. Prusty {
14051b2c425SGeliang Tang 	struct hdac_device *hdac = dev_to_hdac_dev(dev);
141e342ac08SSubhransu S. Prusty 
14251b2c425SGeliang Tang 	return to_ehdac_device(hdac);
143e342ac08SSubhransu S. Prusty }
144e342ac08SSubhransu S. Prusty 
1452428bca3SSubhransu S. Prusty static unsigned int sad_format(const u8 *sad)
1462428bca3SSubhransu S. Prusty {
1472428bca3SSubhransu S. Prusty 	return ((sad[0] >> 0x3) & 0x1f);
1482428bca3SSubhransu S. Prusty }
1492428bca3SSubhransu S. Prusty 
1502428bca3SSubhransu S. Prusty static unsigned int sad_sample_bits_lpcm(const u8 *sad)
1512428bca3SSubhransu S. Prusty {
1522428bca3SSubhransu S. Prusty 	return (sad[2] & 7);
1532428bca3SSubhransu S. Prusty }
1542428bca3SSubhransu S. Prusty 
1552428bca3SSubhransu S. Prusty static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime,
1562428bca3SSubhransu S. Prusty 						void *eld)
1572428bca3SSubhransu S. Prusty {
1582428bca3SSubhransu S. Prusty 	u64 formats = SNDRV_PCM_FMTBIT_S16;
1592428bca3SSubhransu S. Prusty 	int i;
1602428bca3SSubhransu S. Prusty 	const u8 *sad, *eld_buf = eld;
1612428bca3SSubhransu S. Prusty 
1622428bca3SSubhransu S. Prusty 	sad = drm_eld_sad(eld_buf);
1632428bca3SSubhransu S. Prusty 	if (!sad)
1642428bca3SSubhransu S. Prusty 		goto format_constraint;
1652428bca3SSubhransu S. Prusty 
1662428bca3SSubhransu S. Prusty 	for (i = drm_eld_sad_count(eld_buf); i > 0; i--, sad += 3) {
1672428bca3SSubhransu S. Prusty 		if (sad_format(sad) == 1) { /* AUDIO_CODING_TYPE_LPCM */
1682428bca3SSubhransu S. Prusty 
1692428bca3SSubhransu S. Prusty 			/*
1702428bca3SSubhransu S. Prusty 			 * the controller support 20 and 24 bits in 32 bit
1712428bca3SSubhransu S. Prusty 			 * container so we set S32
1722428bca3SSubhransu S. Prusty 			 */
1732428bca3SSubhransu S. Prusty 			if (sad_sample_bits_lpcm(sad) & 0x6)
1742428bca3SSubhransu S. Prusty 				formats |= SNDRV_PCM_FMTBIT_S32;
1752428bca3SSubhransu S. Prusty 		}
1762428bca3SSubhransu S. Prusty 	}
1772428bca3SSubhransu S. Prusty 
1782428bca3SSubhransu S. Prusty format_constraint:
1792428bca3SSubhransu S. Prusty 	return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT,
1802428bca3SSubhransu S. Prusty 				formats);
1812428bca3SSubhransu S. Prusty 
1822428bca3SSubhransu S. Prusty }
1832428bca3SSubhransu S. Prusty 
184b0362adbSSubhransu S. Prusty static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
185b0362adbSSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid,
186b0362adbSSubhransu S. Prusty 				u32 stream_tag, int format)
187b0362adbSSubhransu S. Prusty {
188b0362adbSSubhransu S. Prusty 	unsigned int val;
189b0362adbSSubhransu S. Prusty 
190b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
191b0362adbSSubhransu S. Prusty 			cvt_nid, pin_nid, stream_tag, format);
192b0362adbSSubhransu S. Prusty 
193b0362adbSSubhransu S. Prusty 	val = (stream_tag << 4);
194b0362adbSSubhransu S. Prusty 
195b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
196b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, val);
197b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
198b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, format);
199b0362adbSSubhransu S. Prusty 
200b0362adbSSubhransu S. Prusty 	return 0;
201b0362adbSSubhransu S. Prusty }
202b0362adbSSubhransu S. Prusty 
203a657f1d0SSubhransu S. Prusty static void
204a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
205a657f1d0SSubhransu S. Prusty 				int packet_index, int byte_index)
206a657f1d0SSubhransu S. Prusty {
207a657f1d0SSubhransu S. Prusty 	int val;
208a657f1d0SSubhransu S. Prusty 
209a657f1d0SSubhransu S. Prusty 	val = (packet_index << 5) | (byte_index & 0x1f);
210a657f1d0SSubhransu S. Prusty 
211a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
212a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_INDEX, val);
213a657f1d0SSubhransu S. Prusty }
214a657f1d0SSubhransu S. Prusty 
215478f544eSSubhransu S. Prusty struct dp_audio_infoframe {
216478f544eSSubhransu S. Prusty 	u8 type; /* 0x84 */
217478f544eSSubhransu S. Prusty 	u8 len;  /* 0x1b */
218478f544eSSubhransu S. Prusty 	u8 ver;  /* 0x11 << 2 */
219478f544eSSubhransu S. Prusty 
220478f544eSSubhransu S. Prusty 	u8 CC02_CT47;	/* match with HDMI infoframe from this on */
221478f544eSSubhransu S. Prusty 	u8 SS01_SF24;
222478f544eSSubhransu S. Prusty 	u8 CXT04;
223478f544eSSubhransu S. Prusty 	u8 CA;
224478f544eSSubhransu S. Prusty 	u8 LFEPBL01_LSV36_DM_INH7;
225478f544eSSubhransu S. Prusty };
226478f544eSSubhransu S. Prusty 
227a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
228a657f1d0SSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid)
229a657f1d0SSubhransu S. Prusty {
230a657f1d0SSubhransu S. Prusty 	uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
231a657f1d0SSubhransu S. Prusty 	struct hdmi_audio_infoframe frame;
232478f544eSSubhransu S. Prusty 	struct dp_audio_infoframe dp_ai;
233478f544eSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
234478f544eSSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
235478f544eSSubhransu S. Prusty 	u8 *dip;
236a657f1d0SSubhransu S. Prusty 	int ret;
237a657f1d0SSubhransu S. Prusty 	int i;
238478f544eSSubhransu S. Prusty 	const u8 *eld_buf;
239478f544eSSubhransu S. Prusty 	u8 conn_type;
240bcced704SSubhransu S. Prusty 	int channels, ca;
241a657f1d0SSubhransu S. Prusty 
242478f544eSSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
243478f544eSSubhransu S. Prusty 		if (pin->nid == pin_nid)
244478f544eSSubhransu S. Prusty 			break;
245478f544eSSubhransu S. Prusty 	}
246a657f1d0SSubhransu S. Prusty 
247bcced704SSubhransu S. Prusty 	ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc,
248bcced704SSubhransu S. Prusty 			pin->channels, pin->chmap_set, true, pin->chmap);
249bcced704SSubhransu S. Prusty 
250bcced704SSubhransu S. Prusty 	channels = snd_hdac_get_active_channels(ca);
251bcced704SSubhransu S. Prusty 	hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels);
252bcced704SSubhransu S. Prusty 
253bcced704SSubhransu S. Prusty 	snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca,
254bcced704SSubhransu S. Prusty 				pin->channels, pin->chmap, pin->chmap_set);
255bcced704SSubhransu S. Prusty 
256478f544eSSubhransu S. Prusty 	eld_buf = pin->eld.eld_buffer;
257478f544eSSubhransu S. Prusty 	conn_type = drm_eld_get_conn_type(eld_buf);
258a657f1d0SSubhransu S. Prusty 
259478f544eSSubhransu S. Prusty 	switch (conn_type) {
260478f544eSSubhransu S. Prusty 	case DRM_ELD_CONN_TYPE_HDMI:
261478f544eSSubhransu S. Prusty 		hdmi_audio_infoframe_init(&frame);
262478f544eSSubhransu S. Prusty 
263478f544eSSubhransu S. Prusty 		frame.channels = channels;
264bcced704SSubhransu S. Prusty 		frame.channel_allocation = ca;
265a657f1d0SSubhransu S. Prusty 
266a657f1d0SSubhransu S. Prusty 		ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
267a657f1d0SSubhransu S. Prusty 		if (ret < 0)
268a657f1d0SSubhransu S. Prusty 			return ret;
269a657f1d0SSubhransu S. Prusty 
270478f544eSSubhransu S. Prusty 		break;
271478f544eSSubhransu S. Prusty 
272478f544eSSubhransu S. Prusty 	case DRM_ELD_CONN_TYPE_DP:
273478f544eSSubhransu S. Prusty 		memset(&dp_ai, 0, sizeof(dp_ai));
274478f544eSSubhransu S. Prusty 		dp_ai.type	= 0x84;
275478f544eSSubhransu S. Prusty 		dp_ai.len	= 0x1b;
276478f544eSSubhransu S. Prusty 		dp_ai.ver	= 0x11 << 2;
277478f544eSSubhransu S. Prusty 		dp_ai.CC02_CT47	= channels - 1;
278bcced704SSubhransu S. Prusty 		dp_ai.CA	= ca;
279478f544eSSubhransu S. Prusty 
280478f544eSSubhransu S. Prusty 		dip = (u8 *)&dp_ai;
281478f544eSSubhransu S. Prusty 		break;
282478f544eSSubhransu S. Prusty 
283478f544eSSubhransu S. Prusty 	default:
284478f544eSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Invalid connection type: %d\n",
285478f544eSSubhransu S. Prusty 						conn_type);
286478f544eSSubhransu S. Prusty 		return -EIO;
287478f544eSSubhransu S. Prusty 	}
288478f544eSSubhransu S. Prusty 
289a657f1d0SSubhransu S. Prusty 	/* stop infoframe transmission */
290a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
291a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
292a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
293a657f1d0SSubhransu S. Prusty 
294a657f1d0SSubhransu S. Prusty 
295a657f1d0SSubhransu S. Prusty 	/*  Fill infoframe. Index auto-incremented */
296a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
297478f544eSSubhransu S. Prusty 	if (conn_type == DRM_ELD_CONN_TYPE_HDMI) {
298391005e8SSubhransu S. Prusty 		for (i = 0; i < sizeof(buffer); i++)
299a657f1d0SSubhransu S. Prusty 			snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
300391005e8SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_DATA, buffer[i]);
301478f544eSSubhransu S. Prusty 	} else {
302478f544eSSubhransu S. Prusty 		for (i = 0; i < sizeof(dp_ai); i++)
303478f544eSSubhransu S. Prusty 			snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
304478f544eSSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
305478f544eSSubhransu S. Prusty 	}
306a657f1d0SSubhransu S. Prusty 
307a657f1d0SSubhransu S. Prusty 	/* Start infoframe */
308a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
309a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
310a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
311a657f1d0SSubhransu S. Prusty 
312a657f1d0SSubhransu S. Prusty 	return 0;
313a657f1d0SSubhransu S. Prusty }
314a657f1d0SSubhransu S. Prusty 
315b0362adbSSubhransu S. Prusty static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
316b0362adbSSubhransu S. Prusty 		struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
317b0362adbSSubhransu S. Prusty {
318b0362adbSSubhransu S. Prusty 	/* Power up pin widget */
31915b91447SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
32015b91447SSubhransu S. Prusty 						pwr_state))
32115b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
322b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
323b0362adbSSubhransu S. Prusty 
324b0362adbSSubhransu S. Prusty 	/* Power up converter */
32515b91447SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
32615b91447SSubhransu S. Prusty 						pwr_state))
32715b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
328b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
329b0362adbSSubhransu S. Prusty }
330b0362adbSSubhransu S. Prusty 
331b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
332b0362adbSSubhransu S. Prusty 				struct snd_soc_dai *dai)
333b0362adbSSubhransu S. Prusty {
334b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
335b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
336b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
337bcced704SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
338b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
339a657f1d0SSubhransu S. Prusty 	int ret;
340b0362adbSSubhransu S. Prusty 
341b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
342bcced704SSubhransu S. Prusty 	pin = dai_map->pin;
343b0362adbSSubhransu S. Prusty 
344b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
345b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
346b0362adbSSubhransu S. Prusty 			dd->stream_tag,	dd->format);
347b0362adbSSubhransu S. Prusty 
3481de777feSJeeja KP 	hdac_hdmi_enable_cvt(hdac, dai_map);
3491de777feSJeeja KP 	ret = hdac_hdmi_enable_pin(hdac, dai_map);
3501de777feSJeeja KP 	if (ret < 0)
3511de777feSJeeja KP 		return ret;
352bcced704SSubhransu S. Prusty 	mutex_lock(&pin->lock);
353bcced704SSubhransu S. Prusty 	pin->channels = substream->runtime->channels;
354bcced704SSubhransu S. Prusty 
35515b91447SSubhransu S. Prusty 	ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
35615b91447SSubhransu S. Prusty 						dai_map->pin->nid);
357bcced704SSubhransu S. Prusty 	mutex_unlock(&pin->lock);
358a657f1d0SSubhransu S. Prusty 	if (ret < 0)
359a657f1d0SSubhransu S. Prusty 		return ret;
360a657f1d0SSubhransu S. Prusty 
36115b91447SSubhransu S. Prusty 	return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
36215b91447SSubhransu S. Prusty 			dai_map->pin->nid, dd->stream_tag, dd->format);
363b0362adbSSubhransu S. Prusty }
364b0362adbSSubhransu S. Prusty 
365b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
366b0362adbSSubhransu S. Prusty 	struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
367b0362adbSSubhransu S. Prusty {
368b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
36954dfa1eaSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
37054dfa1eaSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
37154dfa1eaSSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
372b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
373b0362adbSSubhransu S. Prusty 
37454dfa1eaSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
37554dfa1eaSSubhransu S. Prusty 	pin = dai_map->pin;
37654dfa1eaSSubhransu S. Prusty 
37754dfa1eaSSubhransu S. Prusty 	if (!pin)
37854dfa1eaSSubhransu S. Prusty 		return -ENODEV;
37954dfa1eaSSubhransu S. Prusty 
38054dfa1eaSSubhransu S. Prusty 	if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) {
38154dfa1eaSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "device is not configured for this pin: %d\n",
38254dfa1eaSSubhransu S. Prusty 								pin->nid);
383b0362adbSSubhransu S. Prusty 		return -ENODEV;
384b0362adbSSubhransu S. Prusty 	}
385b0362adbSSubhransu S. Prusty 
3866793a3d7SSubhransu S. Prusty 	dd = snd_soc_dai_get_dma_data(dai, substream);
3876793a3d7SSubhransu S. Prusty 	if (!dd) {
388b0362adbSSubhransu S. Prusty 		dd = kzalloc(sizeof(*dd), GFP_KERNEL);
3898d33ab24SSudip Mukherjee 		if (!dd)
3908d33ab24SSudip Mukherjee 			return -ENOMEM;
3916793a3d7SSubhransu S. Prusty 	}
3926793a3d7SSubhransu S. Prusty 
393b0362adbSSubhransu S. Prusty 	dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
394b0362adbSSubhransu S. Prusty 			params_channels(hparams), params_format(hparams),
395b0362adbSSubhransu S. Prusty 			24, 0);
396b0362adbSSubhransu S. Prusty 
397b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
398b0362adbSSubhransu S. Prusty 
399b0362adbSSubhransu S. Prusty 	return 0;
400b0362adbSSubhransu S. Prusty }
401b0362adbSSubhransu S. Prusty 
402b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
403b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
404b0362adbSSubhransu S. Prusty {
405b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
406b0362adbSSubhransu S. Prusty 
407b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
408b0362adbSSubhransu S. Prusty 
4096793a3d7SSubhransu S. Prusty 	if (dd) {
4106793a3d7SSubhransu S. Prusty 		snd_soc_dai_set_dma_data(dai, substream, NULL);
411b0362adbSSubhransu S. Prusty 		kfree(dd);
4126793a3d7SSubhransu S. Prusty 	}
413b0362adbSSubhransu S. Prusty 
414b0362adbSSubhransu S. Prusty 	return 0;
415b0362adbSSubhransu S. Prusty }
416b0362adbSSubhransu S. Prusty 
417ab85f5b3SSubhransu S. Prusty static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev,
418ab85f5b3SSubhransu S. Prusty 		struct hdac_hdmi_dai_pin_map *dai_map)
419ab85f5b3SSubhransu S. Prusty {
420ab85f5b3SSubhransu S. Prusty 	/* Enable transmission */
421ab85f5b3SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
422ab85f5b3SSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_1, 1);
423ab85f5b3SSubhransu S. Prusty 
424ab85f5b3SSubhransu S. Prusty 	/* Category Code (CC) to zero */
425ab85f5b3SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
426ab85f5b3SSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_2, 0);
427ab85f5b3SSubhransu S. Prusty }
428ab85f5b3SSubhransu S. Prusty 
429148569fdSSubhransu S. Prusty static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac,
430148569fdSSubhransu S. Prusty 		struct hdac_hdmi_dai_pin_map *dai_map)
431148569fdSSubhransu S. Prusty {
432148569fdSSubhransu S. Prusty 	int mux_idx;
433148569fdSSubhransu S. Prusty 	struct hdac_hdmi_pin *pin = dai_map->pin;
434148569fdSSubhransu S. Prusty 
435148569fdSSubhransu S. Prusty 	for (mux_idx = 0; mux_idx < pin->num_mux_nids; mux_idx++) {
436148569fdSSubhransu S. Prusty 		if (pin->mux_nids[mux_idx] == dai_map->cvt->nid) {
437148569fdSSubhransu S. Prusty 			snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
438148569fdSSubhransu S. Prusty 					AC_VERB_SET_CONNECT_SEL, mux_idx);
439148569fdSSubhransu S. Prusty 			break;
440148569fdSSubhransu S. Prusty 		}
441148569fdSSubhransu S. Prusty 	}
442148569fdSSubhransu S. Prusty 
443148569fdSSubhransu S. Prusty 	if (mux_idx == pin->num_mux_nids)
444148569fdSSubhransu S. Prusty 		return -EIO;
445148569fdSSubhransu S. Prusty 
446148569fdSSubhransu S. Prusty 	/* Enable out path for this pin widget */
447148569fdSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
448148569fdSSubhransu S. Prusty 			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
449148569fdSSubhransu S. Prusty 
450148569fdSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
451148569fdSSubhransu S. Prusty 
452148569fdSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
453148569fdSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
454148569fdSSubhransu S. Prusty 
455148569fdSSubhransu S. Prusty 	return 0;
456148569fdSSubhransu S. Prusty }
457148569fdSSubhransu S. Prusty 
458148569fdSSubhransu S. Prusty static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
459148569fdSSubhransu S. Prusty 					struct hdac_hdmi_pin *pin)
460148569fdSSubhransu S. Prusty {
461148569fdSSubhransu S. Prusty 	if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
462148569fdSSubhransu S. Prusty 		dev_warn(&hdac->hdac.dev,
463148569fdSSubhransu S. Prusty 			"HDMI: pin %d wcaps %#x does not support connection list\n",
464148569fdSSubhransu S. Prusty 			pin->nid, get_wcaps(&hdac->hdac, pin->nid));
465148569fdSSubhransu S. Prusty 		return -EINVAL;
466148569fdSSubhransu S. Prusty 	}
467148569fdSSubhransu S. Prusty 
468148569fdSSubhransu S. Prusty 	pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
469148569fdSSubhransu S. Prusty 			pin->mux_nids, HDA_MAX_CONNECTIONS);
470148569fdSSubhransu S. Prusty 	if (pin->num_mux_nids == 0)
471148569fdSSubhransu S. Prusty 		dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n",
472148569fdSSubhransu S. Prusty 								pin->nid);
473148569fdSSubhransu S. Prusty 
474148569fdSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n",
475148569fdSSubhransu S. Prusty 			pin->num_mux_nids, pin->nid);
476148569fdSSubhransu S. Prusty 
477148569fdSSubhransu S. Prusty 	return pin->num_mux_nids;
478148569fdSSubhransu S. Prusty }
479148569fdSSubhransu S. Prusty 
480148569fdSSubhransu S. Prusty /*
481148569fdSSubhransu S. Prusty  * Query pcm list and return pin widget to which stream is routed.
482148569fdSSubhransu S. Prusty  *
483148569fdSSubhransu S. Prusty  * Also query connection list of the pin, to validate the cvt to pin map.
484148569fdSSubhransu S. Prusty  *
485148569fdSSubhransu S. Prusty  * Same stream rendering to multiple pins simultaneously can be done
486148569fdSSubhransu S. Prusty  * possibly, but not supported for now in driver. So return the first pin
487148569fdSSubhransu S. Prusty  * connected.
488148569fdSSubhransu S. Prusty  */
489148569fdSSubhransu S. Prusty static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt(
490148569fdSSubhransu S. Prusty 			struct hdac_ext_device *edev,
491148569fdSSubhransu S. Prusty 			struct hdac_hdmi_priv *hdmi,
492148569fdSSubhransu S. Prusty 			struct hdac_hdmi_cvt *cvt)
493148569fdSSubhransu S. Prusty {
494148569fdSSubhransu S. Prusty 	struct hdac_hdmi_pcm *pcm;
495148569fdSSubhransu S. Prusty 	struct hdac_hdmi_pin *pin = NULL;
496148569fdSSubhransu S. Prusty 	int ret, i;
497148569fdSSubhransu S. Prusty 
498148569fdSSubhransu S. Prusty 	list_for_each_entry(pcm, &hdmi->pcm_list, head) {
499148569fdSSubhransu S. Prusty 		if (pcm->cvt == cvt) {
500148569fdSSubhransu S. Prusty 			pin = pcm->pin;
501148569fdSSubhransu S. Prusty 			break;
502148569fdSSubhransu S. Prusty 		}
503148569fdSSubhransu S. Prusty 	}
504148569fdSSubhransu S. Prusty 
505148569fdSSubhransu S. Prusty 	if (pin) {
506148569fdSSubhransu S. Prusty 		ret = hdac_hdmi_query_pin_connlist(edev, pin);
507148569fdSSubhransu S. Prusty 		if (ret < 0)
508148569fdSSubhransu S. Prusty 			return NULL;
509148569fdSSubhransu S. Prusty 
510148569fdSSubhransu S. Prusty 		for (i = 0; i < pin->num_mux_nids; i++) {
511148569fdSSubhransu S. Prusty 			if (pin->mux_nids[i] == cvt->nid)
512148569fdSSubhransu S. Prusty 				return pin;
513148569fdSSubhransu S. Prusty 		}
514148569fdSSubhransu S. Prusty 	}
515148569fdSSubhransu S. Prusty 
516148569fdSSubhransu S. Prusty 	return NULL;
517148569fdSSubhransu S. Prusty }
518148569fdSSubhransu S. Prusty 
51954dfa1eaSSubhransu S. Prusty /*
52054dfa1eaSSubhransu S. Prusty  * This tries to get a valid pin and set the HW constraints based on the
52154dfa1eaSSubhransu S. Prusty  * ELD. Even if a valid pin is not found return success so that device open
52254dfa1eaSSubhransu S. Prusty  * doesn't fail.
52354dfa1eaSSubhransu S. Prusty  */
524b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
525b0362adbSSubhransu S. Prusty 			struct snd_soc_dai *dai)
526b0362adbSSubhransu S. Prusty {
527b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
528b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
529b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
530148569fdSSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
531148569fdSSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
5322428bca3SSubhransu S. Prusty 	int ret;
533b0362adbSSubhransu S. Prusty 
534b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
535b0362adbSSubhransu S. Prusty 
536148569fdSSubhransu S. Prusty 	cvt = dai_map->cvt;
537148569fdSSubhransu S. Prusty 	pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt);
53854dfa1eaSSubhransu S. Prusty 
53954dfa1eaSSubhransu S. Prusty 	/*
54054dfa1eaSSubhransu S. Prusty 	 * To make PA and other userland happy.
54154dfa1eaSSubhransu S. Prusty 	 * userland scans devices so returning error does not help.
54254dfa1eaSSubhransu S. Prusty 	 */
543148569fdSSubhransu S. Prusty 	if (!pin)
54454dfa1eaSSubhransu S. Prusty 		return 0;
545148569fdSSubhransu S. Prusty 
546148569fdSSubhransu S. Prusty 	if ((!pin->eld.monitor_present) ||
547148569fdSSubhransu S. Prusty 			(!pin->eld.eld_valid)) {
548b0362adbSSubhransu S. Prusty 
54954dfa1eaSSubhransu S. Prusty 		dev_warn(&hdac->hdac.dev,
5503fb7b4e4SColin Ian King 			"Failed: monitor present? %d ELD valid?: %d for pin: %d\n",
551148569fdSSubhransu S. Prusty 			pin->eld.monitor_present, pin->eld.eld_valid, pin->nid);
552b8a54545SSubhransu S. Prusty 
55354dfa1eaSSubhransu S. Prusty 		return 0;
554b0362adbSSubhransu S. Prusty 	}
555b0362adbSSubhransu S. Prusty 
556148569fdSSubhransu S. Prusty 	dai_map->pin = pin;
557b0362adbSSubhransu S. Prusty 
5582428bca3SSubhransu S. Prusty 	ret = hdac_hdmi_eld_limit_formats(substream->runtime,
559148569fdSSubhransu S. Prusty 				pin->eld.eld_buffer);
5602428bca3SSubhransu S. Prusty 	if (ret < 0)
5612428bca3SSubhransu S. Prusty 		return ret;
562b0362adbSSubhransu S. Prusty 
5632428bca3SSubhransu S. Prusty 	return snd_pcm_hw_constraint_eld(substream->runtime,
564148569fdSSubhransu S. Prusty 				pin->eld.eld_buffer);
565b0362adbSSubhransu S. Prusty }
566b0362adbSSubhransu S. Prusty 
567571d5078SJeeja KP static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
568571d5078SJeeja KP 		struct snd_soc_dai *dai)
569571d5078SJeeja KP {
570571d5078SJeeja KP 
5711de777feSJeeja KP 	switch (cmd) {
5721de777feSJeeja KP 	case SNDRV_PCM_TRIGGER_RESUME:
5731de777feSJeeja KP 	case SNDRV_PCM_TRIGGER_START:
5741de777feSJeeja KP 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
575571d5078SJeeja KP 		return hdac_hdmi_playback_prepare(substream, dai);
5761de777feSJeeja KP 
5771de777feSJeeja KP 	default:
5781de777feSJeeja KP 		return 0;
579571d5078SJeeja KP 	}
580571d5078SJeeja KP 
581571d5078SJeeja KP 	return 0;
582571d5078SJeeja KP }
583571d5078SJeeja KP 
584b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
585b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
586b0362adbSSubhransu S. Prusty {
587b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
588b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
589b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
590b0362adbSSubhransu S. Prusty 
591b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
592b0362adbSSubhransu S. Prusty 
59354dfa1eaSSubhransu S. Prusty 	if (dai_map->pin) {
59454dfa1eaSSubhransu S. Prusty 		snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0,
59554dfa1eaSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, 0);
59654dfa1eaSSubhransu S. Prusty 		snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0,
59754dfa1eaSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, 0);
59854dfa1eaSSubhransu S. Prusty 
599b0362adbSSubhransu S. Prusty 		hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
600b0362adbSSubhransu S. Prusty 
60115b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
602b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
603148569fdSSubhransu S. Prusty 
604bcced704SSubhransu S. Prusty 		mutex_lock(&dai_map->pin->lock);
6052889099eSSubhransu S. Prusty 		dai_map->pin->chmap_set = false;
6062889099eSSubhransu S. Prusty 		memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap));
607bcced704SSubhransu S. Prusty 		dai_map->pin->channels = 0;
608bcced704SSubhransu S. Prusty 		mutex_unlock(&dai_map->pin->lock);
609bcced704SSubhransu S. Prusty 
610148569fdSSubhransu S. Prusty 		dai_map->pin = NULL;
611b0362adbSSubhransu S. Prusty 	}
61254dfa1eaSSubhransu S. Prusty }
613b0362adbSSubhransu S. Prusty 
61418382eadSSubhransu S. Prusty static int
61518382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
61618382eadSSubhransu S. Prusty {
617bcced704SSubhransu S. Prusty 	unsigned int chans;
618bcced704SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_ehdac_device(hdac);
619bcced704SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
62018382eadSSubhransu S. Prusty 	int err;
62118382eadSSubhransu S. Prusty 
622bcced704SSubhransu S. Prusty 	chans = get_wcaps(hdac, cvt->nid);
623bcced704SSubhransu S. Prusty 	chans = get_wcaps_channels(chans);
624bcced704SSubhransu S. Prusty 
625bcced704SSubhransu S. Prusty 	cvt->params.channels_min = 2;
626bcced704SSubhransu S. Prusty 
627bcced704SSubhransu S. Prusty 	cvt->params.channels_max = chans;
628bcced704SSubhransu S. Prusty 	if (chans > hdmi->chmap.channels_max)
629bcced704SSubhransu S. Prusty 		hdmi->chmap.channels_max = chans;
63018382eadSSubhransu S. Prusty 
63118382eadSSubhransu S. Prusty 	err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
63218382eadSSubhransu S. Prusty 			&cvt->params.rates,
63318382eadSSubhransu S. Prusty 			&cvt->params.formats,
63418382eadSSubhransu S. Prusty 			&cvt->params.maxbps);
63518382eadSSubhransu S. Prusty 	if (err < 0)
63618382eadSSubhransu S. Prusty 		dev_err(&hdac->dev,
63718382eadSSubhransu S. Prusty 			"Failed to query pcm params for nid %d: %d\n",
63818382eadSSubhransu S. Prusty 			cvt->nid, err);
63918382eadSSubhransu S. Prusty 
64018382eadSSubhransu S. Prusty 	return err;
64118382eadSSubhransu S. Prusty }
64218382eadSSubhransu S. Prusty 
64379f4e922SSubhransu S. Prusty static int hdac_hdmi_fill_widget_info(struct device *dev,
64479f4e922SSubhransu S. Prusty 				struct snd_soc_dapm_widget *w,
64579f4e922SSubhransu S. Prusty 				enum snd_soc_dapm_type id, void *priv,
64679f4e922SSubhransu S. Prusty 				const char *wname, const char *stream,
64779f4e922SSubhransu S. Prusty 				struct snd_kcontrol_new *wc, int numkc)
64818382eadSSubhransu S. Prusty {
64918382eadSSubhransu S. Prusty 	w->id = id;
65079f4e922SSubhransu S. Prusty 	w->name = devm_kstrdup(dev, wname, GFP_KERNEL);
65179f4e922SSubhransu S. Prusty 	if (!w->name)
65279f4e922SSubhransu S. Prusty 		return -ENOMEM;
65379f4e922SSubhransu S. Prusty 
65418382eadSSubhransu S. Prusty 	w->sname = stream;
65518382eadSSubhransu S. Prusty 	w->reg = SND_SOC_NOPM;
65618382eadSSubhransu S. Prusty 	w->shift = 0;
65779f4e922SSubhransu S. Prusty 	w->kcontrol_news = wc;
65879f4e922SSubhransu S. Prusty 	w->num_kcontrols = numkc;
65979f4e922SSubhransu S. Prusty 	w->priv = priv;
66079f4e922SSubhransu S. Prusty 
66179f4e922SSubhransu S. Prusty 	return 0;
66218382eadSSubhransu S. Prusty }
66318382eadSSubhransu S. Prusty 
66418382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
66579f4e922SSubhransu S. Prusty 		const char *sink, const char *control, const char *src,
66679f4e922SSubhransu S. Prusty 		int (*handler)(struct snd_soc_dapm_widget *src,
66779f4e922SSubhransu S. Prusty 			struct snd_soc_dapm_widget *sink))
66818382eadSSubhransu S. Prusty {
66918382eadSSubhransu S. Prusty 	route->sink = sink;
67018382eadSSubhransu S. Prusty 	route->source = src;
67118382eadSSubhransu S. Prusty 	route->control = control;
67279f4e922SSubhransu S. Prusty 	route->connected = handler;
67318382eadSSubhransu S. Prusty }
67418382eadSSubhransu S. Prusty 
6754a3478deSJeeja KP static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
6764a3478deSJeeja KP 					struct hdac_hdmi_pin *pin)
6774a3478deSJeeja KP {
6784a3478deSJeeja KP 	struct hdac_hdmi_priv *hdmi = edev->private_data;
6794a3478deSJeeja KP 	struct hdac_hdmi_pcm *pcm = NULL;
6804a3478deSJeeja KP 
6814a3478deSJeeja KP 	list_for_each_entry(pcm, &hdmi->pcm_list, head) {
6824a3478deSJeeja KP 		if (pcm->pin == pin)
6834a3478deSJeeja KP 			return pcm;
6844a3478deSJeeja KP 	}
6854a3478deSJeeja KP 
6864a3478deSJeeja KP 	return NULL;
6874a3478deSJeeja KP }
6884a3478deSJeeja KP 
6894a3478deSJeeja KP /*
6904a3478deSJeeja KP  * Based on user selection, map the PINs with the PCMs.
6914a3478deSJeeja KP  */
6924a3478deSJeeja KP static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol,
6934a3478deSJeeja KP 		struct snd_ctl_elem_value *ucontrol)
6944a3478deSJeeja KP {
6954a3478deSJeeja KP 	int ret;
6964a3478deSJeeja KP 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
6974a3478deSJeeja KP 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
6984a3478deSJeeja KP 	struct snd_soc_dapm_context *dapm = w->dapm;
6994a3478deSJeeja KP 	struct hdac_hdmi_pin *pin = w->priv;
7004a3478deSJeeja KP 	struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
7014a3478deSJeeja KP 	struct hdac_hdmi_priv *hdmi = edev->private_data;
7024a3478deSJeeja KP 	struct hdac_hdmi_pcm *pcm = NULL;
7034a3478deSJeeja KP 	const char *cvt_name =  e->texts[ucontrol->value.enumerated.item[0]];
7044a3478deSJeeja KP 
7054a3478deSJeeja KP 	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
7064a3478deSJeeja KP 	if (ret < 0)
7074a3478deSJeeja KP 		return ret;
7084a3478deSJeeja KP 
7094a3478deSJeeja KP 	mutex_lock(&hdmi->pin_mutex);
7104a3478deSJeeja KP 	list_for_each_entry(pcm, &hdmi->pcm_list, head) {
7114a3478deSJeeja KP 		if (pcm->pin == pin)
7124a3478deSJeeja KP 			pcm->pin = NULL;
7134a3478deSJeeja KP 
7144a3478deSJeeja KP 		/*
7154a3478deSJeeja KP 		 * Jack status is not reported during device probe as the
7164a3478deSJeeja KP 		 * PCMs are not registered by then. So report it here.
7174a3478deSJeeja KP 		 */
7184a3478deSJeeja KP 		if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) {
7194a3478deSJeeja KP 			pcm->pin = pin;
7204a3478deSJeeja KP 			if (pin->eld.monitor_present && pin->eld.eld_valid) {
7214a3478deSJeeja KP 				dev_dbg(&edev->hdac.dev,
7224a3478deSJeeja KP 					"jack report for pcm=%d\n",
7234a3478deSJeeja KP 					pcm->pcm_id);
7244a3478deSJeeja KP 
7254a3478deSJeeja KP 				snd_jack_report(pcm->jack, SND_JACK_AVOUT);
7264a3478deSJeeja KP 			}
7274a3478deSJeeja KP 			mutex_unlock(&hdmi->pin_mutex);
7284a3478deSJeeja KP 			return ret;
7294a3478deSJeeja KP 		}
7304a3478deSJeeja KP 	}
7314a3478deSJeeja KP 	mutex_unlock(&hdmi->pin_mutex);
7324a3478deSJeeja KP 
7334a3478deSJeeja KP 	return ret;
7344a3478deSJeeja KP }
7354a3478deSJeeja KP 
73679f4e922SSubhransu S. Prusty /*
73779f4e922SSubhransu S. Prusty  * Ideally the Mux inputs should be based on the num_muxs enumerated, but
73879f4e922SSubhransu S. Prusty  * the display driver seem to be programming the connection list for the pin
73979f4e922SSubhransu S. Prusty  * widget runtime.
74079f4e922SSubhransu S. Prusty  *
74179f4e922SSubhransu S. Prusty  * So programming all the possible inputs for the mux, the user has to take
74279f4e922SSubhransu S. Prusty  * care of selecting the right one and leaving all other inputs selected to
74379f4e922SSubhransu S. Prusty  * "NONE"
74479f4e922SSubhransu S. Prusty  */
74579f4e922SSubhransu S. Prusty static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev,
74679f4e922SSubhransu S. Prusty 				struct hdac_hdmi_pin *pin,
74779f4e922SSubhransu S. Prusty 				struct snd_soc_dapm_widget *widget,
74879f4e922SSubhransu S. Prusty 				const char *widget_name)
74918382eadSSubhransu S. Prusty {
75079f4e922SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
75179f4e922SSubhransu S. Prusty 	struct snd_kcontrol_new *kc;
75279f4e922SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
75379f4e922SSubhransu S. Prusty 	struct soc_enum *se;
75479f4e922SSubhransu S. Prusty 	char kc_name[NAME_SIZE];
75579f4e922SSubhransu S. Prusty 	char mux_items[NAME_SIZE];
75679f4e922SSubhransu S. Prusty 	/* To hold inputs to the Pin mux */
75779f4e922SSubhransu S. Prusty 	char *items[HDA_MAX_CONNECTIONS];
75879f4e922SSubhransu S. Prusty 	int i = 0;
75979f4e922SSubhransu S. Prusty 	int num_items = hdmi->num_cvt + 1;
76018382eadSSubhransu S. Prusty 
76179f4e922SSubhransu S. Prusty 	kc = devm_kzalloc(&edev->hdac.dev, sizeof(*kc), GFP_KERNEL);
76279f4e922SSubhransu S. Prusty 	if (!kc)
76379f4e922SSubhransu S. Prusty 		return -ENOMEM;
76418382eadSSubhransu S. Prusty 
76579f4e922SSubhransu S. Prusty 	se = devm_kzalloc(&edev->hdac.dev, sizeof(*se), GFP_KERNEL);
76679f4e922SSubhransu S. Prusty 	if (!se)
76779f4e922SSubhransu S. Prusty 		return -ENOMEM;
76818382eadSSubhransu S. Prusty 
76979f4e922SSubhransu S. Prusty 	sprintf(kc_name, "Pin %d Input", pin->nid);
77079f4e922SSubhransu S. Prusty 	kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL);
77179f4e922SSubhransu S. Prusty 	if (!kc->name)
77279f4e922SSubhransu S. Prusty 		return -ENOMEM;
77318382eadSSubhransu S. Prusty 
77479f4e922SSubhransu S. Prusty 	kc->private_value = (long)se;
77579f4e922SSubhransu S. Prusty 	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
77679f4e922SSubhransu S. Prusty 	kc->access = 0;
77779f4e922SSubhransu S. Prusty 	kc->info = snd_soc_info_enum_double;
7784a3478deSJeeja KP 	kc->put = hdac_hdmi_set_pin_mux;
77979f4e922SSubhransu S. Prusty 	kc->get = snd_soc_dapm_get_enum_double;
78079f4e922SSubhransu S. Prusty 
78179f4e922SSubhransu S. Prusty 	se->reg = SND_SOC_NOPM;
78279f4e922SSubhransu S. Prusty 
78379f4e922SSubhransu S. Prusty 	/* enum texts: ["NONE", "cvt #", "cvt #", ...] */
78479f4e922SSubhransu S. Prusty 	se->items = num_items;
78579f4e922SSubhransu S. Prusty 	se->mask = roundup_pow_of_two(se->items) - 1;
78679f4e922SSubhransu S. Prusty 
78779f4e922SSubhransu S. Prusty 	sprintf(mux_items, "NONE");
78879f4e922SSubhransu S. Prusty 	items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL);
78979f4e922SSubhransu S. Prusty 	if (!items[i])
79079f4e922SSubhransu S. Prusty 		return -ENOMEM;
79179f4e922SSubhransu S. Prusty 
79279f4e922SSubhransu S. Prusty 	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
79379f4e922SSubhransu S. Prusty 		i++;
79479f4e922SSubhransu S. Prusty 		sprintf(mux_items, "cvt %d", cvt->nid);
79579f4e922SSubhransu S. Prusty 		items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL);
79679f4e922SSubhransu S. Prusty 		if (!items[i])
79779f4e922SSubhransu S. Prusty 			return -ENOMEM;
79879f4e922SSubhransu S. Prusty 	}
79979f4e922SSubhransu S. Prusty 
80079f4e922SSubhransu S. Prusty 	se->texts = devm_kmemdup(&edev->hdac.dev, items,
80179f4e922SSubhransu S. Prusty 			(num_items  * sizeof(char *)), GFP_KERNEL);
80279f4e922SSubhransu S. Prusty 	if (!se->texts)
80379f4e922SSubhransu S. Prusty 		return -ENOMEM;
80479f4e922SSubhransu S. Prusty 
80579f4e922SSubhransu S. Prusty 	return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget,
8064a3478deSJeeja KP 			snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1);
80779f4e922SSubhransu S. Prusty }
80879f4e922SSubhransu S. Prusty 
80979f4e922SSubhransu S. Prusty /* Add cvt <- input <- mux route map */
81079f4e922SSubhransu S. Prusty static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev,
81179f4e922SSubhransu S. Prusty 			struct snd_soc_dapm_widget *widgets,
81279f4e922SSubhransu S. Prusty 			struct snd_soc_dapm_route *route, int rindex)
81379f4e922SSubhransu S. Prusty {
81479f4e922SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
81579f4e922SSubhransu S. Prusty 	const struct snd_kcontrol_new *kc;
81679f4e922SSubhransu S. Prusty 	struct soc_enum *se;
81779f4e922SSubhransu S. Prusty 	int mux_index = hdmi->num_cvt + hdmi->num_pin;
81879f4e922SSubhransu S. Prusty 	int i, j;
81979f4e922SSubhransu S. Prusty 
82079f4e922SSubhransu S. Prusty 	for (i = 0; i < hdmi->num_pin; i++) {
82179f4e922SSubhransu S. Prusty 		kc = widgets[mux_index].kcontrol_news;
82279f4e922SSubhransu S. Prusty 		se = (struct soc_enum *)kc->private_value;
82379f4e922SSubhransu S. Prusty 		for (j = 0; j < hdmi->num_cvt; j++) {
82479f4e922SSubhransu S. Prusty 			hdac_hdmi_fill_route(&route[rindex],
82579f4e922SSubhransu S. Prusty 					widgets[mux_index].name,
82679f4e922SSubhransu S. Prusty 					se->texts[j + 1],
82779f4e922SSubhransu S. Prusty 					widgets[j].name, NULL);
82879f4e922SSubhransu S. Prusty 
82979f4e922SSubhransu S. Prusty 			rindex++;
83079f4e922SSubhransu S. Prusty 		}
83179f4e922SSubhransu S. Prusty 
83279f4e922SSubhransu S. Prusty 		mux_index++;
83379f4e922SSubhransu S. Prusty 	}
83479f4e922SSubhransu S. Prusty }
83579f4e922SSubhransu S. Prusty 
83679f4e922SSubhransu S. Prusty /*
83779f4e922SSubhransu S. Prusty  * Widgets are added in the below sequence
83879f4e922SSubhransu S. Prusty  *	Converter widgets for num converters enumerated
83979f4e922SSubhransu S. Prusty  *	Pin widgets for num pins enumerated
84079f4e922SSubhransu S. Prusty  *	Pin mux widgets to represent connenction list of pin widget
84179f4e922SSubhransu S. Prusty  *
84279f4e922SSubhransu S. Prusty  * Total widgets elements = num_cvt + num_pin + num_pin;
84379f4e922SSubhransu S. Prusty  *
84479f4e922SSubhransu S. Prusty  * Routes are added as below:
84579f4e922SSubhransu S. Prusty  *	pin mux -> pin (based on num_pins)
84679f4e922SSubhransu S. Prusty  *	cvt -> "Input sel control" -> pin_mux
84779f4e922SSubhransu S. Prusty  *
84879f4e922SSubhransu S. Prusty  * Total route elements:
84979f4e922SSubhransu S. Prusty  *	num_pins + (pin_muxes * num_cvt)
85079f4e922SSubhransu S. Prusty  */
85179f4e922SSubhransu S. Prusty static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
85279f4e922SSubhransu S. Prusty {
85379f4e922SSubhransu S. Prusty 	struct snd_soc_dapm_widget *widgets;
85479f4e922SSubhransu S. Prusty 	struct snd_soc_dapm_route *route;
85579f4e922SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
85679f4e922SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
85779f4e922SSubhransu S. Prusty 	struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv;
85879f4e922SSubhransu S. Prusty 	char widget_name[NAME_SIZE];
85979f4e922SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
86079f4e922SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
86179f4e922SSubhransu S. Prusty 	int ret, i = 0, num_routes = 0;
86279f4e922SSubhransu S. Prusty 
86379f4e922SSubhransu S. Prusty 	if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
86479f4e922SSubhransu S. Prusty 		return -EINVAL;
86579f4e922SSubhransu S. Prusty 
86679f4e922SSubhransu S. Prusty 	widgets = devm_kzalloc(dapm->dev,
86779f4e922SSubhransu S. Prusty 		(sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)),
86879f4e922SSubhransu S. Prusty 		GFP_KERNEL);
86979f4e922SSubhransu S. Prusty 
87079f4e922SSubhransu S. Prusty 	if (!widgets)
87179f4e922SSubhransu S. Prusty 		return -ENOMEM;
87279f4e922SSubhransu S. Prusty 
87379f4e922SSubhransu S. Prusty 	/* DAPM widgets to represent each converter widget */
87479f4e922SSubhransu S. Prusty 	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
87579f4e922SSubhransu S. Prusty 		sprintf(widget_name, "Converter %d", cvt->nid);
87679f4e922SSubhransu S. Prusty 		ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
87779f4e922SSubhransu S. Prusty 			snd_soc_dapm_aif_in, &cvt->nid,
87879f4e922SSubhransu S. Prusty 			widget_name, dai_drv[i].playback.stream_name, NULL, 0);
87979f4e922SSubhransu S. Prusty 		if (ret < 0)
88079f4e922SSubhransu S. Prusty 			return ret;
88179f4e922SSubhransu S. Prusty 		i++;
88279f4e922SSubhransu S. Prusty 	}
88379f4e922SSubhransu S. Prusty 
88479f4e922SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
88579f4e922SSubhransu S. Prusty 		sprintf(widget_name, "hif%d Output", pin->nid);
88679f4e922SSubhransu S. Prusty 		ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
88779f4e922SSubhransu S. Prusty 				snd_soc_dapm_output, &pin->nid,
88879f4e922SSubhransu S. Prusty 				widget_name, NULL, NULL, 0);
88979f4e922SSubhransu S. Prusty 		if (ret < 0)
89079f4e922SSubhransu S. Prusty 			return ret;
89179f4e922SSubhransu S. Prusty 		i++;
89279f4e922SSubhransu S. Prusty 	}
89379f4e922SSubhransu S. Prusty 
89479f4e922SSubhransu S. Prusty 	/* DAPM widgets to represent the connection list to pin widget */
89579f4e922SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
89679f4e922SSubhransu S. Prusty 		sprintf(widget_name, "Pin %d Mux", pin->nid);
89779f4e922SSubhransu S. Prusty 		ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i],
89879f4e922SSubhransu S. Prusty 							widget_name);
89979f4e922SSubhransu S. Prusty 		if (ret < 0)
90079f4e922SSubhransu S. Prusty 			return ret;
90179f4e922SSubhransu S. Prusty 		i++;
90279f4e922SSubhransu S. Prusty 
90379f4e922SSubhransu S. Prusty 		/* For cvt to pin_mux mapping */
90479f4e922SSubhransu S. Prusty 		num_routes += hdmi->num_cvt;
90579f4e922SSubhransu S. Prusty 
90679f4e922SSubhransu S. Prusty 		/* For pin_mux to pin mapping */
90779f4e922SSubhransu S. Prusty 		num_routes++;
90879f4e922SSubhransu S. Prusty 	}
90979f4e922SSubhransu S. Prusty 
91079f4e922SSubhransu S. Prusty 	route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes),
91179f4e922SSubhransu S. Prusty 							GFP_KERNEL);
91279f4e922SSubhransu S. Prusty 	if (!route)
91379f4e922SSubhransu S. Prusty 		return -ENOMEM;
91479f4e922SSubhransu S. Prusty 
91579f4e922SSubhransu S. Prusty 	i = 0;
91679f4e922SSubhransu S. Prusty 	/* Add pin <- NULL <- mux route map */
91779f4e922SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
91879f4e922SSubhransu S. Prusty 		int sink_index = i + hdmi->num_cvt;
91979f4e922SSubhransu S. Prusty 		int src_index = sink_index + hdmi->num_pin;
92079f4e922SSubhransu S. Prusty 
92179f4e922SSubhransu S. Prusty 		hdac_hdmi_fill_route(&route[i],
92279f4e922SSubhransu S. Prusty 				widgets[sink_index].name, NULL,
92379f4e922SSubhransu S. Prusty 				widgets[src_index].name, NULL);
92479f4e922SSubhransu S. Prusty 		i++;
92579f4e922SSubhransu S. Prusty 
92679f4e922SSubhransu S. Prusty 	}
92779f4e922SSubhransu S. Prusty 
92879f4e922SSubhransu S. Prusty 	hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i);
92979f4e922SSubhransu S. Prusty 
93079f4e922SSubhransu S. Prusty 	snd_soc_dapm_new_controls(dapm, widgets,
93179f4e922SSubhransu S. Prusty 		((2 * hdmi->num_pin) + hdmi->num_cvt));
93279f4e922SSubhransu S. Prusty 
93379f4e922SSubhransu S. Prusty 	snd_soc_dapm_add_routes(dapm, route, num_routes);
93479f4e922SSubhransu S. Prusty 	snd_soc_dapm_new_widgets(dapm->card);
93579f4e922SSubhransu S. Prusty 
93679f4e922SSubhransu S. Prusty 	return 0;
93779f4e922SSubhransu S. Prusty 
93818382eadSSubhransu S. Prusty }
93918382eadSSubhransu S. Prusty 
94015b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
94118382eadSSubhransu S. Prusty {
94215b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
943148569fdSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
94415b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
945148569fdSSubhransu S. Prusty 	int dai_id = 0;
94618382eadSSubhransu S. Prusty 
947148569fdSSubhransu S. Prusty 	if (list_empty(&hdmi->cvt_list))
94815b91447SSubhransu S. Prusty 		return -EINVAL;
94918382eadSSubhransu S. Prusty 
950148569fdSSubhransu S. Prusty 	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
951148569fdSSubhransu S. Prusty 		dai_map = &hdmi->dai_map[dai_id];
952148569fdSSubhransu S. Prusty 		dai_map->dai_id = dai_id;
95315b91447SSubhransu S. Prusty 		dai_map->cvt = cvt;
95418382eadSSubhransu S. Prusty 
955148569fdSSubhransu S. Prusty 		dai_id++;
956148569fdSSubhransu S. Prusty 
957148569fdSSubhransu S. Prusty 		if (dai_id == HDA_MAX_CVTS) {
958148569fdSSubhransu S. Prusty 			dev_warn(&edev->hdac.dev,
959148569fdSSubhransu S. Prusty 				"Max dais supported: %d\n", dai_id);
960148569fdSSubhransu S. Prusty 			break;
961148569fdSSubhransu S. Prusty 		}
962148569fdSSubhransu S. Prusty 	}
96318382eadSSubhransu S. Prusty 
96415b91447SSubhransu S. Prusty 	return 0;
96515b91447SSubhransu S. Prusty }
96615b91447SSubhransu S. Prusty 
96715b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
96815b91447SSubhransu S. Prusty {
96915b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
97015b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
9714a3478deSJeeja KP 	char name[NAME_SIZE];
97215b91447SSubhransu S. Prusty 
97315b91447SSubhransu S. Prusty 	cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
97415b91447SSubhransu S. Prusty 	if (!cvt)
97515b91447SSubhransu S. Prusty 		return -ENOMEM;
97615b91447SSubhransu S. Prusty 
97715b91447SSubhransu S. Prusty 	cvt->nid = nid;
9784a3478deSJeeja KP 	sprintf(name, "cvt %d", cvt->nid);
9794a3478deSJeeja KP 	cvt->name = kstrdup(name, GFP_KERNEL);
98015b91447SSubhransu S. Prusty 
98115b91447SSubhransu S. Prusty 	list_add_tail(&cvt->head, &hdmi->cvt_list);
98215b91447SSubhransu S. Prusty 	hdmi->num_cvt++;
98315b91447SSubhransu S. Prusty 
98415b91447SSubhransu S. Prusty 	return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
98515b91447SSubhransu S. Prusty }
98615b91447SSubhransu S. Prusty 
987f6fa11a3SSandeep Tayal static int  hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
988b7756edeSSubhransu S. Prusty 			struct hdac_hdmi_pin *pin)
989b7756edeSSubhransu S. Prusty {
990f6fa11a3SSandeep Tayal 	unsigned int ver, mnl;
991f6fa11a3SSandeep Tayal 
992f6fa11a3SSandeep Tayal 	ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK)
993f6fa11a3SSandeep Tayal 						>> DRM_ELD_VER_SHIFT;
994f6fa11a3SSandeep Tayal 
995f6fa11a3SSandeep Tayal 	if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) {
996f6fa11a3SSandeep Tayal 		dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver);
997f6fa11a3SSandeep Tayal 		return -EINVAL;
998b7756edeSSubhransu S. Prusty 	}
999b7756edeSSubhransu S. Prusty 
1000f6fa11a3SSandeep Tayal 	mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] &
1001f6fa11a3SSandeep Tayal 		DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
1002f6fa11a3SSandeep Tayal 
1003f6fa11a3SSandeep Tayal 	if (mnl > ELD_MAX_MNL) {
1004f6fa11a3SSandeep Tayal 		dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl);
1005f6fa11a3SSandeep Tayal 		return -EINVAL;
1006f6fa11a3SSandeep Tayal 	}
1007f6fa11a3SSandeep Tayal 
1008f6fa11a3SSandeep Tayal 	pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER];
1009f6fa11a3SSandeep Tayal 
1010f6fa11a3SSandeep Tayal 	return 0;
1011f6fa11a3SSandeep Tayal }
1012f6fa11a3SSandeep Tayal 
1013f6fa11a3SSandeep Tayal static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin)
1014b8a54545SSubhransu S. Prusty {
1015b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev = pin->edev;
10164a3478deSJeeja KP 	struct hdac_hdmi_priv *hdmi = edev->private_data;
10174a3478deSJeeja KP 	struct hdac_hdmi_pcm *pcm;
1018f6fa11a3SSandeep Tayal 	int size;
10194a3478deSJeeja KP 
10204a3478deSJeeja KP 	mutex_lock(&hdmi->pin_mutex);
1021f6fa11a3SSandeep Tayal 	pin->eld.monitor_present = false;
1022f6fa11a3SSandeep Tayal 
1023f6fa11a3SSandeep Tayal 	size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1,
1024f6fa11a3SSandeep Tayal 				&pin->eld.monitor_present, pin->eld.eld_buffer,
1025f6fa11a3SSandeep Tayal 				ELD_MAX_SIZE);
1026f6fa11a3SSandeep Tayal 
1027f6fa11a3SSandeep Tayal 	if (size > 0) {
1028f6fa11a3SSandeep Tayal 		size = min(size, ELD_MAX_SIZE);
1029f6fa11a3SSandeep Tayal 		if (hdac_hdmi_parse_eld(edev, pin) < 0)
1030f6fa11a3SSandeep Tayal 			size = -EINVAL;
1031f6fa11a3SSandeep Tayal 	}
1032f6fa11a3SSandeep Tayal 
1033f6fa11a3SSandeep Tayal 	if (size > 0) {
1034f6fa11a3SSandeep Tayal 		pin->eld.eld_valid = true;
1035f6fa11a3SSandeep Tayal 		pin->eld.eld_size = size;
1036f6fa11a3SSandeep Tayal 	} else {
1037f6fa11a3SSandeep Tayal 		pin->eld.eld_valid = false;
1038f6fa11a3SSandeep Tayal 		pin->eld.eld_size = 0;
1039f6fa11a3SSandeep Tayal 	}
1040b8a54545SSubhransu S. Prusty 
10414a3478deSJeeja KP 	pcm = hdac_hdmi_get_pcm(edev, pin);
10424a3478deSJeeja KP 
1043b8a54545SSubhransu S. Prusty 	if (!pin->eld.monitor_present || !pin->eld.eld_valid) {
1044b8a54545SSubhransu S. Prusty 
1045b8a54545SSubhransu S. Prusty 		dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n",
1046b8a54545SSubhransu S. Prusty 						__func__, pin->nid);
10474a3478deSJeeja KP 
10484a3478deSJeeja KP 		/*
10494a3478deSJeeja KP 		 * PCMs are not registered during device probe, so don't
10504a3478deSJeeja KP 		 * report jack here. It will be done in usermode mux
10514a3478deSJeeja KP 		 * control select.
10524a3478deSJeeja KP 		 */
10534a3478deSJeeja KP 		if (pcm) {
10544a3478deSJeeja KP 			dev_dbg(&edev->hdac.dev,
10554a3478deSJeeja KP 				"jack report for pcm=%d\n", pcm->pcm_id);
10564a3478deSJeeja KP 
10574a3478deSJeeja KP 			snd_jack_report(pcm->jack, 0);
10584a3478deSJeeja KP 		}
10594a3478deSJeeja KP 
10604a3478deSJeeja KP 		mutex_unlock(&hdmi->pin_mutex);
1061f6fa11a3SSandeep Tayal 		return;
1062b8a54545SSubhransu S. Prusty 	}
1063b8a54545SSubhransu S. Prusty 
1064b8a54545SSubhransu S. Prusty 	if (pin->eld.monitor_present && pin->eld.eld_valid) {
10654a3478deSJeeja KP 		if (pcm) {
10664a3478deSJeeja KP 			dev_dbg(&edev->hdac.dev,
10674a3478deSJeeja KP 				"jack report for pcm=%d\n",
10684a3478deSJeeja KP 				pcm->pcm_id);
10694a3478deSJeeja KP 
10704a3478deSJeeja KP 			snd_jack_report(pcm->jack, SND_JACK_AVOUT);
10714a3478deSJeeja KP 		}
10724a3478deSJeeja KP 
1073f6fa11a3SSandeep Tayal 		print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1,
1074f6fa11a3SSandeep Tayal 			  pin->eld.eld_buffer, pin->eld.eld_size, false);
10754a3478deSJeeja KP 	}
10764a3478deSJeeja KP 
10774a3478deSJeeja KP 	mutex_unlock(&hdmi->pin_mutex);
1078b8a54545SSubhransu S. Prusty }
1079b8a54545SSubhransu S. Prusty 
108015b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
108115b91447SSubhransu S. Prusty {
108215b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
108315b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
108415b91447SSubhransu S. Prusty 
108515b91447SSubhransu S. Prusty 	pin = kzalloc(sizeof(*pin), GFP_KERNEL);
108615b91447SSubhransu S. Prusty 	if (!pin)
108715b91447SSubhransu S. Prusty 		return -ENOMEM;
108815b91447SSubhransu S. Prusty 
108915b91447SSubhransu S. Prusty 	pin->nid = nid;
109015b91447SSubhransu S. Prusty 
109115b91447SSubhransu S. Prusty 	list_add_tail(&pin->head, &hdmi->pin_list);
109215b91447SSubhransu S. Prusty 	hdmi->num_pin++;
109315b91447SSubhransu S. Prusty 
1094b8a54545SSubhransu S. Prusty 	pin->edev = edev;
1095bcced704SSubhransu S. Prusty 	mutex_init(&pin->lock);
1096b8a54545SSubhransu S. Prusty 
109715b91447SSubhransu S. Prusty 	return 0;
109818382eadSSubhransu S. Prusty }
109918382eadSSubhransu S. Prusty 
1100211caab7SSubhransu S. Prusty #define INTEL_VENDOR_NID 0x08
1101211caab7SSubhransu S. Prusty #define INTEL_GET_VENDOR_VERB 0xf81
1102211caab7SSubhransu S. Prusty #define INTEL_SET_VENDOR_VERB 0x781
1103211caab7SSubhransu S. Prusty #define INTEL_EN_DP12			0x02 /* enable DP 1.2 features */
1104211caab7SSubhransu S. Prusty #define INTEL_EN_ALL_PIN_CVTS	0x01 /* enable 2nd & 3rd pins and convertors */
1105211caab7SSubhransu S. Prusty 
1106211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
1107211caab7SSubhransu S. Prusty {
1108211caab7SSubhransu S. Prusty 	unsigned int vendor_param;
1109211caab7SSubhransu S. Prusty 
1110211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
1111211caab7SSubhransu S. Prusty 				INTEL_GET_VENDOR_VERB, 0);
1112211caab7SSubhransu S. Prusty 	if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
1113211caab7SSubhransu S. Prusty 		return;
1114211caab7SSubhransu S. Prusty 
1115211caab7SSubhransu S. Prusty 	vendor_param |= INTEL_EN_ALL_PIN_CVTS;
1116211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
1117211caab7SSubhransu S. Prusty 				INTEL_SET_VENDOR_VERB, vendor_param);
1118211caab7SSubhransu S. Prusty 	if (vendor_param == -1)
1119211caab7SSubhransu S. Prusty 		return;
1120211caab7SSubhransu S. Prusty }
1121211caab7SSubhransu S. Prusty 
1122211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
1123211caab7SSubhransu S. Prusty {
1124211caab7SSubhransu S. Prusty 	unsigned int vendor_param;
1125211caab7SSubhransu S. Prusty 
1126211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
1127211caab7SSubhransu S. Prusty 				INTEL_GET_VENDOR_VERB, 0);
1128211caab7SSubhransu S. Prusty 	if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
1129211caab7SSubhransu S. Prusty 		return;
1130211caab7SSubhransu S. Prusty 
1131211caab7SSubhransu S. Prusty 	/* enable DP1.2 mode */
1132211caab7SSubhransu S. Prusty 	vendor_param |= INTEL_EN_DP12;
1133211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
1134211caab7SSubhransu S. Prusty 				INTEL_SET_VENDOR_VERB, vendor_param);
1135211caab7SSubhransu S. Prusty 	if (vendor_param == -1)
1136211caab7SSubhransu S. Prusty 		return;
1137211caab7SSubhransu S. Prusty 
1138211caab7SSubhransu S. Prusty }
1139211caab7SSubhransu S. Prusty 
114017a42c45SSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = {
114117a42c45SSubhransu S. Prusty 	.startup = hdac_hdmi_pcm_open,
114217a42c45SSubhransu S. Prusty 	.shutdown = hdac_hdmi_pcm_close,
114317a42c45SSubhransu S. Prusty 	.hw_params = hdac_hdmi_set_hw_params,
114417a42c45SSubhransu S. Prusty 	.prepare = hdac_hdmi_playback_prepare,
1145571d5078SJeeja KP 	.trigger = hdac_hdmi_trigger,
114617a42c45SSubhransu S. Prusty 	.hw_free = hdac_hdmi_playback_cleanup,
114717a42c45SSubhransu S. Prusty };
114817a42c45SSubhransu S. Prusty 
114917a42c45SSubhransu S. Prusty /*
115017a42c45SSubhransu S. Prusty  * Each converter can support a stream independently. So a dai is created
115117a42c45SSubhransu S. Prusty  * based on the number of converter queried.
115217a42c45SSubhransu S. Prusty  */
115317a42c45SSubhransu S. Prusty static int hdac_hdmi_create_dais(struct hdac_device *hdac,
115417a42c45SSubhransu S. Prusty 		struct snd_soc_dai_driver **dais,
115517a42c45SSubhransu S. Prusty 		struct hdac_hdmi_priv *hdmi, int num_dais)
115617a42c45SSubhransu S. Prusty {
115717a42c45SSubhransu S. Prusty 	struct snd_soc_dai_driver *hdmi_dais;
115817a42c45SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
115917a42c45SSubhransu S. Prusty 	char name[NAME_SIZE], dai_name[NAME_SIZE];
116017a42c45SSubhransu S. Prusty 	int i = 0;
116117a42c45SSubhransu S. Prusty 	u32 rates, bps;
116217a42c45SSubhransu S. Prusty 	unsigned int rate_max = 384000, rate_min = 8000;
116317a42c45SSubhransu S. Prusty 	u64 formats;
116417a42c45SSubhransu S. Prusty 	int ret;
116517a42c45SSubhransu S. Prusty 
116617a42c45SSubhransu S. Prusty 	hdmi_dais = devm_kzalloc(&hdac->dev,
116717a42c45SSubhransu S. Prusty 			(sizeof(*hdmi_dais) * num_dais),
116817a42c45SSubhransu S. Prusty 			GFP_KERNEL);
116917a42c45SSubhransu S. Prusty 	if (!hdmi_dais)
117017a42c45SSubhransu S. Prusty 		return -ENOMEM;
117117a42c45SSubhransu S. Prusty 
117217a42c45SSubhransu S. Prusty 	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
117317a42c45SSubhransu S. Prusty 		ret = snd_hdac_query_supported_pcm(hdac, cvt->nid,
117417a42c45SSubhransu S. Prusty 					&rates,	&formats, &bps);
117517a42c45SSubhransu S. Prusty 		if (ret)
117617a42c45SSubhransu S. Prusty 			return ret;
117717a42c45SSubhransu S. Prusty 
117817a42c45SSubhransu S. Prusty 		sprintf(dai_name, "intel-hdmi-hifi%d", i+1);
117917a42c45SSubhransu S. Prusty 		hdmi_dais[i].name = devm_kstrdup(&hdac->dev,
118017a42c45SSubhransu S. Prusty 					dai_name, GFP_KERNEL);
118117a42c45SSubhransu S. Prusty 
118217a42c45SSubhransu S. Prusty 		if (!hdmi_dais[i].name)
118317a42c45SSubhransu S. Prusty 			return -ENOMEM;
118417a42c45SSubhransu S. Prusty 
118517a42c45SSubhransu S. Prusty 		snprintf(name, sizeof(name), "hifi%d", i+1);
118617a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.stream_name =
118717a42c45SSubhransu S. Prusty 				devm_kstrdup(&hdac->dev, name, GFP_KERNEL);
118817a42c45SSubhransu S. Prusty 		if (!hdmi_dais[i].playback.stream_name)
118917a42c45SSubhransu S. Prusty 			return -ENOMEM;
119017a42c45SSubhransu S. Prusty 
119117a42c45SSubhransu S. Prusty 		/*
119217a42c45SSubhransu S. Prusty 		 * Set caps based on capability queried from the converter.
119317a42c45SSubhransu S. Prusty 		 * It will be constrained runtime based on ELD queried.
119417a42c45SSubhransu S. Prusty 		 */
119517a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.formats = formats;
119617a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.rates = rates;
119717a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.rate_max = rate_max;
119817a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.rate_min = rate_min;
119917a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.channels_min = 2;
120017a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.channels_max = 2;
120117a42c45SSubhransu S. Prusty 		hdmi_dais[i].ops = &hdmi_dai_ops;
120217a42c45SSubhransu S. Prusty 
120317a42c45SSubhransu S. Prusty 		i++;
120417a42c45SSubhransu S. Prusty 	}
120517a42c45SSubhransu S. Prusty 
120617a42c45SSubhransu S. Prusty 	*dais = hdmi_dais;
120717a42c45SSubhransu S. Prusty 
120817a42c45SSubhransu S. Prusty 	return 0;
120917a42c45SSubhransu S. Prusty }
121017a42c45SSubhransu S. Prusty 
121118382eadSSubhransu S. Prusty /*
121218382eadSSubhransu S. Prusty  * Parse all nodes and store the cvt/pin nids in array
121318382eadSSubhransu S. Prusty  * Add one time initialization for pin and cvt widgets
121418382eadSSubhransu S. Prusty  */
121517a42c45SSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
121617a42c45SSubhransu S. Prusty 		struct snd_soc_dai_driver **dais, int *num_dais)
121718382eadSSubhransu S. Prusty {
121818382eadSSubhransu S. Prusty 	hda_nid_t nid;
12193c83ac23SSudip Mukherjee 	int i, num_nodes;
122018382eadSSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
122118382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
122215b91447SSubhransu S. Prusty 	int ret;
122318382eadSSubhransu S. Prusty 
1224211caab7SSubhransu S. Prusty 	hdac_hdmi_skl_enable_all_pins(hdac);
1225211caab7SSubhransu S. Prusty 	hdac_hdmi_skl_enable_dp12(hdac);
1226211caab7SSubhransu S. Prusty 
12273c83ac23SSudip Mukherjee 	num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
1228541140d4SSubhransu S. Prusty 	if (!nid || num_nodes <= 0) {
122918382eadSSubhransu S. Prusty 		dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
123018382eadSSubhransu S. Prusty 		return -EINVAL;
123118382eadSSubhransu S. Prusty 	}
123218382eadSSubhransu S. Prusty 
12333c83ac23SSudip Mukherjee 	hdac->num_nodes = num_nodes;
123418382eadSSubhransu S. Prusty 	hdac->start_nid = nid;
123518382eadSSubhransu S. Prusty 
123618382eadSSubhransu S. Prusty 	for (i = 0; i < hdac->num_nodes; i++, nid++) {
123718382eadSSubhransu S. Prusty 		unsigned int caps;
123818382eadSSubhransu S. Prusty 		unsigned int type;
123918382eadSSubhransu S. Prusty 
124018382eadSSubhransu S. Prusty 		caps = get_wcaps(hdac, nid);
124118382eadSSubhransu S. Prusty 		type = get_wcaps_type(caps);
124218382eadSSubhransu S. Prusty 
124318382eadSSubhransu S. Prusty 		if (!(caps & AC_WCAP_DIGITAL))
124418382eadSSubhransu S. Prusty 			continue;
124518382eadSSubhransu S. Prusty 
124618382eadSSubhransu S. Prusty 		switch (type) {
124718382eadSSubhransu S. Prusty 
124818382eadSSubhransu S. Prusty 		case AC_WID_AUD_OUT:
124915b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_cvt(edev, nid);
125015b91447SSubhransu S. Prusty 			if (ret < 0)
125115b91447SSubhransu S. Prusty 				return ret;
125218382eadSSubhransu S. Prusty 			break;
125318382eadSSubhransu S. Prusty 
125418382eadSSubhransu S. Prusty 		case AC_WID_PIN:
125515b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_pin(edev, nid);
125615b91447SSubhransu S. Prusty 			if (ret < 0)
125715b91447SSubhransu S. Prusty 				return ret;
125818382eadSSubhransu S. Prusty 			break;
125918382eadSSubhransu S. Prusty 		}
126018382eadSSubhransu S. Prusty 	}
126118382eadSSubhransu S. Prusty 
126218382eadSSubhransu S. Prusty 	hdac->end_nid = nid;
126318382eadSSubhransu S. Prusty 
126415b91447SSubhransu S. Prusty 	if (!hdmi->num_pin || !hdmi->num_cvt)
126518382eadSSubhransu S. Prusty 		return -EIO;
126618382eadSSubhransu S. Prusty 
126717a42c45SSubhransu S. Prusty 	ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt);
126817a42c45SSubhransu S. Prusty 	if (ret) {
126917a42c45SSubhransu S. Prusty 		dev_err(&hdac->dev, "Failed to create dais with err: %d\n",
127017a42c45SSubhransu S. Prusty 							ret);
127117a42c45SSubhransu S. Prusty 		return ret;
127217a42c45SSubhransu S. Prusty 	}
127317a42c45SSubhransu S. Prusty 
127417a42c45SSubhransu S. Prusty 	*num_dais = hdmi->num_cvt;
127517a42c45SSubhransu S. Prusty 
127615b91447SSubhransu S. Prusty 	return hdac_hdmi_init_dai_map(edev);
127718382eadSSubhransu S. Prusty }
127818382eadSSubhransu S. Prusty 
1279b8a54545SSubhransu S. Prusty static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
1280b8a54545SSubhransu S. Prusty {
1281b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev = aptr;
1282b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
1283b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
1284b8a54545SSubhransu S. Prusty 	struct snd_soc_codec *codec = edev->scodec;
1285b8a54545SSubhransu S. Prusty 
1286b8a54545SSubhransu S. Prusty 	/* Don't know how this mapping is derived */
1287b8a54545SSubhransu S. Prusty 	hda_nid_t pin_nid = port + 0x04;
1288b8a54545SSubhransu S. Prusty 
1289b8a54545SSubhransu S. Prusty 	dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid);
1290b8a54545SSubhransu S. Prusty 
1291b8a54545SSubhransu S. Prusty 	/*
1292b8a54545SSubhransu S. Prusty 	 * skip notification during system suspend (but not in runtime PM);
1293b8a54545SSubhransu S. Prusty 	 * the state will be updated at resume. Also since the ELD and
1294b8a54545SSubhransu S. Prusty 	 * connection states are updated in anyway at the end of the resume,
1295b8a54545SSubhransu S. Prusty 	 * we can skip it when received during PM process.
1296b8a54545SSubhransu S. Prusty 	 */
1297b8a54545SSubhransu S. Prusty 	if (snd_power_get_state(codec->component.card->snd_card) !=
1298b8a54545SSubhransu S. Prusty 			SNDRV_CTL_POWER_D0)
1299b8a54545SSubhransu S. Prusty 		return;
1300b8a54545SSubhransu S. Prusty 
1301b8a54545SSubhransu S. Prusty 	if (atomic_read(&edev->hdac.in_pm))
1302b8a54545SSubhransu S. Prusty 		return;
1303b8a54545SSubhransu S. Prusty 
1304b8a54545SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
1305b8a54545SSubhransu S. Prusty 		if (pin->nid == pin_nid)
1306f6fa11a3SSandeep Tayal 			hdac_hdmi_present_sense(pin);
1307b8a54545SSubhransu S. Prusty 	}
1308b8a54545SSubhransu S. Prusty }
1309b8a54545SSubhransu S. Prusty 
1310b8a54545SSubhransu S. Prusty static struct i915_audio_component_audio_ops aops = {
1311b8a54545SSubhransu S. Prusty 	.pin_eld_notify	= hdac_hdmi_eld_notify_cb,
1312b8a54545SSubhransu S. Prusty };
1313b8a54545SSubhransu S. Prusty 
13142889099eSSubhransu S. Prusty static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
13152889099eSSubhransu S. Prusty 						int device)
13162889099eSSubhransu S. Prusty {
13172889099eSSubhransu S. Prusty 	struct snd_soc_pcm_runtime *rtd;
13182889099eSSubhransu S. Prusty 
13192889099eSSubhransu S. Prusty 	list_for_each_entry(rtd, &card->rtd_list, list) {
13202889099eSSubhransu S. Prusty 		if (rtd->pcm && (rtd->pcm->device == device))
13212889099eSSubhransu S. Prusty 			return rtd->pcm;
13222889099eSSubhransu S. Prusty 	}
13232889099eSSubhransu S. Prusty 
13242889099eSSubhransu S. Prusty 	return NULL;
13252889099eSSubhransu S. Prusty }
13262889099eSSubhransu S. Prusty 
13274a3478deSJeeja KP int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
13284a3478deSJeeja KP {
13294a3478deSJeeja KP 	char jack_name[NAME_SIZE];
13304a3478deSJeeja KP 	struct snd_soc_codec *codec = dai->codec;
13314a3478deSJeeja KP 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
13324a3478deSJeeja KP 	struct snd_soc_dapm_context *dapm =
13334a3478deSJeeja KP 		snd_soc_component_get_dapm(&codec->component);
13344a3478deSJeeja KP 	struct hdac_hdmi_priv *hdmi = edev->private_data;
13354a3478deSJeeja KP 	struct hdac_hdmi_pcm *pcm;
13362889099eSSubhransu S. Prusty 	struct snd_pcm *snd_pcm;
13372889099eSSubhransu S. Prusty 	int err;
13384a3478deSJeeja KP 
13394a3478deSJeeja KP 	/*
13404a3478deSJeeja KP 	 * this is a new PCM device, create new pcm and
13414a3478deSJeeja KP 	 * add to the pcm list
13424a3478deSJeeja KP 	 */
13434a3478deSJeeja KP 	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
13444a3478deSJeeja KP 	if (!pcm)
13454a3478deSJeeja KP 		return -ENOMEM;
13464a3478deSJeeja KP 	pcm->pcm_id = device;
13474a3478deSJeeja KP 	pcm->cvt = hdmi->dai_map[dai->id].cvt;
13484a3478deSJeeja KP 
13492889099eSSubhransu S. Prusty 	snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device);
13502889099eSSubhransu S. Prusty 	if (snd_pcm) {
13512889099eSSubhransu S. Prusty 		err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap);
13522889099eSSubhransu S. Prusty 		if (err < 0) {
13532889099eSSubhransu S. Prusty 			dev_err(&edev->hdac.dev,
13542889099eSSubhransu S. Prusty 				"chmap control add failed with err: %d for pcm: %d\n",
13552889099eSSubhransu S. Prusty 				err, device);
13562889099eSSubhransu S. Prusty 			kfree(pcm);
13572889099eSSubhransu S. Prusty 			return err;
13582889099eSSubhransu S. Prusty 		}
13592889099eSSubhransu S. Prusty 	}
13602889099eSSubhransu S. Prusty 
13614a3478deSJeeja KP 	list_add_tail(&pcm->head, &hdmi->pcm_list);
13624a3478deSJeeja KP 
13634a3478deSJeeja KP 	sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device);
13644a3478deSJeeja KP 
13654a3478deSJeeja KP 	return snd_jack_new(dapm->card->snd_card, jack_name,
13664a3478deSJeeja KP 		SND_JACK_AVOUT,	&pcm->jack, true, false);
13674a3478deSJeeja KP }
13684a3478deSJeeja KP EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
13694a3478deSJeeja KP 
137018382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec)
137118382eadSSubhransu S. Prusty {
137218382eadSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
137318382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
137418382eadSSubhransu S. Prusty 	struct snd_soc_dapm_context *dapm =
137518382eadSSubhransu S. Prusty 		snd_soc_component_get_dapm(&codec->component);
1376b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
1377b2047e99SVinod Koul 	struct hdac_ext_link *hlink = NULL;
1378b8a54545SSubhransu S. Prusty 	int ret;
137918382eadSSubhransu S. Prusty 
138018382eadSSubhransu S. Prusty 	edev->scodec = codec;
138118382eadSSubhransu S. Prusty 
1382b2047e99SVinod Koul 	/*
1383b2047e99SVinod Koul 	 * hold the ref while we probe, also no need to drop the ref on
1384b2047e99SVinod Koul 	 * exit, we call pm_runtime_suspend() so that will do for us
1385b2047e99SVinod Koul 	 */
1386b2047e99SVinod Koul 	hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
1387500e06b9SVinod Koul 	if (!hlink) {
1388500e06b9SVinod Koul 		dev_err(&edev->hdac.dev, "hdac link not found\n");
1389500e06b9SVinod Koul 		return -EIO;
1390500e06b9SVinod Koul 	}
1391500e06b9SVinod Koul 
1392b2047e99SVinod Koul 	snd_hdac_ext_bus_link_get(edev->ebus, hlink);
1393b2047e99SVinod Koul 
139479f4e922SSubhransu S. Prusty 	ret = create_fill_widget_route_map(dapm);
139579f4e922SSubhransu S. Prusty 	if (ret < 0)
139679f4e922SSubhransu S. Prusty 		return ret;
139718382eadSSubhransu S. Prusty 
1398b8a54545SSubhransu S. Prusty 	aops.audio_ptr = edev;
1399b8a54545SSubhransu S. Prusty 	ret = snd_hdac_i915_register_notifier(&aops);
1400b8a54545SSubhransu S. Prusty 	if (ret < 0) {
1401b8a54545SSubhransu S. Prusty 		dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n",
1402b8a54545SSubhransu S. Prusty 				ret);
1403b8a54545SSubhransu S. Prusty 		return ret;
1404b8a54545SSubhransu S. Prusty 	}
1405b8a54545SSubhransu S. Prusty 
1406b8a54545SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head)
1407f6fa11a3SSandeep Tayal 		hdac_hdmi_present_sense(pin);
1408b8a54545SSubhransu S. Prusty 
140918382eadSSubhransu S. Prusty 	/* Imp: Store the card pointer in hda_codec */
141018382eadSSubhransu S. Prusty 	edev->card = dapm->card->snd_card;
141118382eadSSubhransu S. Prusty 
1412e342ac08SSubhransu S. Prusty 	/*
1413e342ac08SSubhransu S. Prusty 	 * hdac_device core already sets the state to active and calls
1414e342ac08SSubhransu S. Prusty 	 * get_noresume. So enable runtime and set the device to suspend.
1415e342ac08SSubhransu S. Prusty 	 */
1416e342ac08SSubhransu S. Prusty 	pm_runtime_enable(&edev->hdac.dev);
1417e342ac08SSubhransu S. Prusty 	pm_runtime_put(&edev->hdac.dev);
1418e342ac08SSubhransu S. Prusty 	pm_runtime_suspend(&edev->hdac.dev);
1419e342ac08SSubhransu S. Prusty 
1420e342ac08SSubhransu S. Prusty 	return 0;
1421e342ac08SSubhransu S. Prusty }
1422e342ac08SSubhransu S. Prusty 
1423e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec)
1424e342ac08SSubhransu S. Prusty {
1425e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
1426e342ac08SSubhransu S. Prusty 
1427e342ac08SSubhransu S. Prusty 	pm_runtime_disable(&edev->hdac.dev);
142818382eadSSubhransu S. Prusty 	return 0;
142918382eadSSubhransu S. Prusty }
143018382eadSSubhransu S. Prusty 
1431571d5078SJeeja KP #ifdef CONFIG_PM
14321b377ccdSSubhransu S. Prusty static int hdmi_codec_prepare(struct device *dev)
14331b377ccdSSubhransu S. Prusty {
14341b377ccdSSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
14351b377ccdSSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
14361b377ccdSSubhransu S. Prusty 
14371b377ccdSSubhransu S. Prusty 	pm_runtime_get_sync(&edev->hdac.dev);
14381b377ccdSSubhransu S. Prusty 
14391b377ccdSSubhransu S. Prusty 	/*
14401b377ccdSSubhransu S. Prusty 	 * Power down afg.
14411b377ccdSSubhransu S. Prusty 	 * codec_read is preferred over codec_write to set the power state.
14421b377ccdSSubhransu S. Prusty 	 * This way verb is send to set the power state and response
14431b377ccdSSubhransu S. Prusty 	 * is received. So setting power state is ensured without using loop
14441b377ccdSSubhransu S. Prusty 	 * to read the state.
14451b377ccdSSubhransu S. Prusty 	 */
14461b377ccdSSubhransu S. Prusty 	snd_hdac_codec_read(hdac, hdac->afg, 0,	AC_VERB_SET_POWER_STATE,
14471b377ccdSSubhransu S. Prusty 							AC_PWRST_D3);
14481b377ccdSSubhransu S. Prusty 
14491b377ccdSSubhransu S. Prusty 	return 0;
14501b377ccdSSubhransu S. Prusty }
14511b377ccdSSubhransu S. Prusty 
14520fee1798SSubhransu S. Prusty static void hdmi_codec_complete(struct device *dev)
1453571d5078SJeeja KP {
14540fee1798SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
1455571d5078SJeeja KP 	struct hdac_hdmi_priv *hdmi = edev->private_data;
1456571d5078SJeeja KP 	struct hdac_hdmi_pin *pin;
1457571d5078SJeeja KP 	struct hdac_device *hdac = &edev->hdac;
14581b377ccdSSubhransu S. Prusty 
14591b377ccdSSubhransu S. Prusty 	/* Power up afg */
14601b377ccdSSubhransu S. Prusty 	snd_hdac_codec_read(hdac, hdac->afg, 0,	AC_VERB_SET_POWER_STATE,
14611b377ccdSSubhransu S. Prusty 							AC_PWRST_D0);
1462571d5078SJeeja KP 
1463571d5078SJeeja KP 	hdac_hdmi_skl_enable_all_pins(&edev->hdac);
1464571d5078SJeeja KP 	hdac_hdmi_skl_enable_dp12(&edev->hdac);
1465571d5078SJeeja KP 
1466571d5078SJeeja KP 	/*
1467571d5078SJeeja KP 	 * As the ELD notify callback request is not entertained while the
1468571d5078SJeeja KP 	 * device is in suspend state. Need to manually check detection of
1469571d5078SJeeja KP 	 * all pins here.
1470571d5078SJeeja KP 	 */
1471571d5078SJeeja KP 	list_for_each_entry(pin, &hdmi->pin_list, head)
1472f6fa11a3SSandeep Tayal 		hdac_hdmi_present_sense(pin);
1473571d5078SJeeja KP 
14741b377ccdSSubhransu S. Prusty 	pm_runtime_put_sync(&edev->hdac.dev);
1475571d5078SJeeja KP }
1476571d5078SJeeja KP #else
14771b377ccdSSubhransu S. Prusty #define hdmi_codec_prepare NULL
14780fee1798SSubhransu S. Prusty #define hdmi_codec_complete NULL
1479571d5078SJeeja KP #endif
1480571d5078SJeeja KP 
148118382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = {
148218382eadSSubhransu S. Prusty 	.probe		= hdmi_codec_probe,
1483e342ac08SSubhransu S. Prusty 	.remove		= hdmi_codec_remove,
148418382eadSSubhransu S. Prusty 	.idle_bias_off	= true,
148518382eadSSubhransu S. Prusty };
148618382eadSSubhransu S. Prusty 
14872889099eSSubhransu S. Prusty static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
14882889099eSSubhransu S. Prusty 					unsigned char *chmap)
14892889099eSSubhransu S. Prusty {
14902889099eSSubhransu S. Prusty 	struct hdac_ext_device *edev = to_ehdac_device(hdac);
14912889099eSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
14922889099eSSubhransu S. Prusty 	struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
14932889099eSSubhransu S. Prusty 	struct hdac_hdmi_pin *pin = pcm->pin;
14942889099eSSubhransu S. Prusty 
14952889099eSSubhransu S. Prusty 	/* chmap is already set to 0 in caller */
14962889099eSSubhransu S. Prusty 	if (!pin)
14972889099eSSubhransu S. Prusty 		return;
14982889099eSSubhransu S. Prusty 
14992889099eSSubhransu S. Prusty 	memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap));
15002889099eSSubhransu S. Prusty }
15012889099eSSubhransu S. Prusty 
15022889099eSSubhransu S. Prusty static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
15032889099eSSubhransu S. Prusty 				unsigned char *chmap, int prepared)
15042889099eSSubhransu S. Prusty {
15052889099eSSubhransu S. Prusty 	struct hdac_ext_device *edev = to_ehdac_device(hdac);
15062889099eSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
15072889099eSSubhransu S. Prusty 	struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
15082889099eSSubhransu S. Prusty 	struct hdac_hdmi_pin *pin = pcm->pin;
15092889099eSSubhransu S. Prusty 
15102889099eSSubhransu S. Prusty 	mutex_lock(&pin->lock);
15112889099eSSubhransu S. Prusty 	pin->chmap_set = true;
15122889099eSSubhransu S. Prusty 	memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap));
15132889099eSSubhransu S. Prusty 	if (prepared)
15142889099eSSubhransu S. Prusty 		hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid);
15152889099eSSubhransu S. Prusty 	mutex_unlock(&pin->lock);
15162889099eSSubhransu S. Prusty }
15172889099eSSubhransu S. Prusty 
15182889099eSSubhransu S. Prusty static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
15192889099eSSubhransu S. Prusty {
15202889099eSSubhransu S. Prusty 	struct hdac_ext_device *edev = to_ehdac_device(hdac);
15212889099eSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
15222889099eSSubhransu S. Prusty 	struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
15232889099eSSubhransu S. Prusty 	struct hdac_hdmi_pin *pin = pcm->pin;
15242889099eSSubhransu S. Prusty 
15252889099eSSubhransu S. Prusty 	return pin ? true:false;
15262889099eSSubhransu S. Prusty }
15272889099eSSubhransu S. Prusty 
15282889099eSSubhransu S. Prusty static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
15292889099eSSubhransu S. Prusty {
15302889099eSSubhransu S. Prusty 	struct hdac_ext_device *edev = to_ehdac_device(hdac);
15312889099eSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
15322889099eSSubhransu S. Prusty 	struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
15332889099eSSubhransu S. Prusty 	struct hdac_hdmi_pin *pin = pcm->pin;
15342889099eSSubhransu S. Prusty 
15358f658815SDan Carpenter 	if (!pin || !pin->eld.eld_valid)
15362889099eSSubhransu S. Prusty 		return 0;
15372889099eSSubhransu S. Prusty 
15382889099eSSubhransu S. Prusty 	return pin->eld.info.spk_alloc;
15392889099eSSubhransu S. Prusty }
15402889099eSSubhransu S. Prusty 
154118382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
154218382eadSSubhransu S. Prusty {
154318382eadSSubhransu S. Prusty 	struct hdac_device *codec = &edev->hdac;
154418382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi_priv;
154517a42c45SSubhransu S. Prusty 	struct snd_soc_dai_driver *hdmi_dais = NULL;
1546b2047e99SVinod Koul 	struct hdac_ext_link *hlink = NULL;
154717a42c45SSubhransu S. Prusty 	int num_dais = 0;
154818382eadSSubhransu S. Prusty 	int ret = 0;
154918382eadSSubhransu S. Prusty 
1550b2047e99SVinod Koul 	/* hold the ref while we probe */
1551b2047e99SVinod Koul 	hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
1552500e06b9SVinod Koul 	if (!hlink) {
1553500e06b9SVinod Koul 		dev_err(&edev->hdac.dev, "hdac link not found\n");
1554500e06b9SVinod Koul 		return -EIO;
1555500e06b9SVinod Koul 	}
1556500e06b9SVinod Koul 
1557b2047e99SVinod Koul 	snd_hdac_ext_bus_link_get(edev->ebus, hlink);
1558b2047e99SVinod Koul 
155918382eadSSubhransu S. Prusty 	hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
156018382eadSSubhransu S. Prusty 	if (hdmi_priv == NULL)
156118382eadSSubhransu S. Prusty 		return -ENOMEM;
156218382eadSSubhransu S. Prusty 
156318382eadSSubhransu S. Prusty 	edev->private_data = hdmi_priv;
1564bcced704SSubhransu S. Prusty 	snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap);
15652889099eSSubhransu S. Prusty 	hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap;
15662889099eSSubhransu S. Prusty 	hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap;
15672889099eSSubhransu S. Prusty 	hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
15682889099eSSubhransu S. Prusty 	hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
156918382eadSSubhransu S. Prusty 
157018382eadSSubhransu S. Prusty 	dev_set_drvdata(&codec->dev, edev);
157118382eadSSubhransu S. Prusty 
157215b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->pin_list);
157315b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->cvt_list);
15744a3478deSJeeja KP 	INIT_LIST_HEAD(&hdmi_priv->pcm_list);
15754a3478deSJeeja KP 	mutex_init(&hdmi_priv->pin_mutex);
157615b91447SSubhransu S. Prusty 
1577aeaccef0SRamesh Babu 	/*
1578aeaccef0SRamesh Babu 	 * Turned off in the runtime_suspend during the first explicit
1579aeaccef0SRamesh Babu 	 * pm_runtime_suspend call.
1580aeaccef0SRamesh Babu 	 */
1581aeaccef0SRamesh Babu 	ret = snd_hdac_display_power(edev->hdac.bus, true);
1582aeaccef0SRamesh Babu 	if (ret < 0) {
1583aeaccef0SRamesh Babu 		dev_err(&edev->hdac.dev,
1584aeaccef0SRamesh Babu 			"Cannot turn on display power on i915 err: %d\n",
1585aeaccef0SRamesh Babu 			ret);
1586aeaccef0SRamesh Babu 		return ret;
1587aeaccef0SRamesh Babu 	}
1588aeaccef0SRamesh Babu 
158917a42c45SSubhransu S. Prusty 	ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais);
159017a42c45SSubhransu S. Prusty 	if (ret < 0) {
159117a42c45SSubhransu S. Prusty 		dev_err(&codec->dev,
159217a42c45SSubhransu S. Prusty 			"Failed in parse and map nid with err: %d\n", ret);
159318382eadSSubhransu S. Prusty 		return ret;
159417a42c45SSubhransu S. Prusty 	}
159518382eadSSubhransu S. Prusty 
159618382eadSSubhransu S. Prusty 	/* ASoC specific initialization */
1597b2047e99SVinod Koul 	ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
159817a42c45SSubhransu S. Prusty 					hdmi_dais, num_dais);
1599b2047e99SVinod Koul 
1600b2047e99SVinod Koul 	snd_hdac_ext_bus_link_put(edev->ebus, hlink);
1601b2047e99SVinod Koul 
1602b2047e99SVinod Koul 	return ret;
160318382eadSSubhransu S. Prusty }
160418382eadSSubhransu S. Prusty 
160518382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
160618382eadSSubhransu S. Prusty {
160715b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
160815b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin, *pin_next;
160915b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt, *cvt_next;
16104a3478deSJeeja KP 	struct hdac_hdmi_pcm *pcm, *pcm_next;
161115b91447SSubhransu S. Prusty 
161218382eadSSubhransu S. Prusty 	snd_soc_unregister_codec(&edev->hdac.dev);
161318382eadSSubhransu S. Prusty 
16144a3478deSJeeja KP 	list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) {
16154a3478deSJeeja KP 		pcm->cvt = NULL;
16164a3478deSJeeja KP 		pcm->pin = NULL;
16174a3478deSJeeja KP 		list_del(&pcm->head);
16184a3478deSJeeja KP 		kfree(pcm);
16194a3478deSJeeja KP 	}
16204a3478deSJeeja KP 
162115b91447SSubhransu S. Prusty 	list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
162215b91447SSubhransu S. Prusty 		list_del(&cvt->head);
16234a3478deSJeeja KP 		kfree(cvt->name);
162415b91447SSubhransu S. Prusty 		kfree(cvt);
162515b91447SSubhransu S. Prusty 	}
162615b91447SSubhransu S. Prusty 
162715b91447SSubhransu S. Prusty 	list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
162815b91447SSubhransu S. Prusty 		list_del(&pin->head);
162915b91447SSubhransu S. Prusty 		kfree(pin);
163015b91447SSubhransu S. Prusty 	}
163115b91447SSubhransu S. Prusty 
163218382eadSSubhransu S. Prusty 	return 0;
163318382eadSSubhransu S. Prusty }
163418382eadSSubhransu S. Prusty 
1635e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM
1636e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev)
1637e342ac08SSubhransu S. Prusty {
1638e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
1639e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
164007f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
1641b2047e99SVinod Koul 	struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
1642b2047e99SVinod Koul 	struct hdac_ext_link *hlink = NULL;
164307f083abSSubhransu S. Prusty 	int err;
1644e342ac08SSubhransu S. Prusty 
1645e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
1646e342ac08SSubhransu S. Prusty 
164707f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
164807f083abSSubhransu S. Prusty 	if (!bus)
164907f083abSSubhransu S. Prusty 		return 0;
165007f083abSSubhransu S. Prusty 
16511b377ccdSSubhransu S. Prusty 	/*
16521b377ccdSSubhransu S. Prusty 	 * Power down afg.
16531b377ccdSSubhransu S. Prusty 	 * codec_read is preferred over codec_write to set the power state.
16541b377ccdSSubhransu S. Prusty 	 * This way verb is send to set the power state and response
16551b377ccdSSubhransu S. Prusty 	 * is received. So setting power state is ensured without using loop
16561b377ccdSSubhransu S. Prusty 	 * to read the state.
16571b377ccdSSubhransu S. Prusty 	 */
16581b377ccdSSubhransu S. Prusty 	snd_hdac_codec_read(hdac, hdac->afg, 0,	AC_VERB_SET_POWER_STATE,
16591b377ccdSSubhransu S. Prusty 							AC_PWRST_D3);
166007f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, false);
166107f083abSSubhransu S. Prusty 	if (err < 0) {
166207f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
166307f083abSSubhransu S. Prusty 		return err;
166407f083abSSubhransu S. Prusty 	}
166507f083abSSubhransu S. Prusty 
1666b2047e99SVinod Koul 	hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
1667500e06b9SVinod Koul 	if (!hlink) {
1668500e06b9SVinod Koul 		dev_err(dev, "hdac link not found\n");
1669500e06b9SVinod Koul 		return -EIO;
1670500e06b9SVinod Koul 	}
1671500e06b9SVinod Koul 
1672b2047e99SVinod Koul 	snd_hdac_ext_bus_link_put(ebus, hlink);
1673b2047e99SVinod Koul 
1674e342ac08SSubhransu S. Prusty 	return 0;
1675e342ac08SSubhransu S. Prusty }
1676e342ac08SSubhransu S. Prusty 
1677e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev)
1678e342ac08SSubhransu S. Prusty {
1679e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
1680e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
168107f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
1682b2047e99SVinod Koul 	struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
1683b2047e99SVinod Koul 	struct hdac_ext_link *hlink = NULL;
168407f083abSSubhransu S. Prusty 	int err;
1685e342ac08SSubhransu S. Prusty 
1686e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
1687e342ac08SSubhransu S. Prusty 
168807f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
168907f083abSSubhransu S. Prusty 	if (!bus)
169007f083abSSubhransu S. Prusty 		return 0;
169107f083abSSubhransu S. Prusty 
1692b2047e99SVinod Koul 	hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
1693500e06b9SVinod Koul 	if (!hlink) {
1694500e06b9SVinod Koul 		dev_err(dev, "hdac link not found\n");
1695500e06b9SVinod Koul 		return -EIO;
1696500e06b9SVinod Koul 	}
1697500e06b9SVinod Koul 
1698b2047e99SVinod Koul 	snd_hdac_ext_bus_link_get(ebus, hlink);
1699b2047e99SVinod Koul 
170007f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, true);
170107f083abSSubhransu S. Prusty 	if (err < 0) {
170207f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
170307f083abSSubhransu S. Prusty 		return err;
170407f083abSSubhransu S. Prusty 	}
170507f083abSSubhransu S. Prusty 
1706ab85f5b3SSubhransu S. Prusty 	hdac_hdmi_skl_enable_all_pins(&edev->hdac);
1707ab85f5b3SSubhransu S. Prusty 	hdac_hdmi_skl_enable_dp12(&edev->hdac);
1708ab85f5b3SSubhransu S. Prusty 
1709e342ac08SSubhransu S. Prusty 	/* Power up afg */
17101b377ccdSSubhransu S. Prusty 	snd_hdac_codec_read(hdac, hdac->afg, 0,	AC_VERB_SET_POWER_STATE,
17111b377ccdSSubhransu S. Prusty 							AC_PWRST_D0);
1712e342ac08SSubhransu S. Prusty 
1713e342ac08SSubhransu S. Prusty 	return 0;
1714e342ac08SSubhransu S. Prusty }
1715e342ac08SSubhransu S. Prusty #else
1716e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL
1717e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL
1718e342ac08SSubhransu S. Prusty #endif
1719e342ac08SSubhransu S. Prusty 
1720e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = {
1721e342ac08SSubhransu S. Prusty 	SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
17221b377ccdSSubhransu S. Prusty 	.prepare = hdmi_codec_prepare,
17230fee1798SSubhransu S. Prusty 	.complete = hdmi_codec_complete,
1724e342ac08SSubhransu S. Prusty };
1725e342ac08SSubhransu S. Prusty 
172618382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = {
172718382eadSSubhransu S. Prusty 	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
1728e2304803SJeeja KP 	HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
1729cc216887SShreyas NC 	HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0),
173018382eadSSubhransu S. Prusty 	{}
173118382eadSSubhransu S. Prusty };
173218382eadSSubhransu S. Prusty 
173318382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
173418382eadSSubhransu S. Prusty 
173518382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = {
173618382eadSSubhransu S. Prusty 	. hdac = {
173718382eadSSubhransu S. Prusty 		.driver = {
173818382eadSSubhransu S. Prusty 			.name   = "HDMI HDA Codec",
1739e342ac08SSubhransu S. Prusty 			.pm = &hdac_hdmi_pm,
174018382eadSSubhransu S. Prusty 		},
174118382eadSSubhransu S. Prusty 		.id_table       = hdmi_list,
174218382eadSSubhransu S. Prusty 	},
174318382eadSSubhransu S. Prusty 	.probe          = hdac_hdmi_dev_probe,
174418382eadSSubhransu S. Prusty 	.remove         = hdac_hdmi_dev_remove,
174518382eadSSubhransu S. Prusty };
174618382eadSSubhransu S. Prusty 
174718382eadSSubhransu S. Prusty static int __init hdmi_init(void)
174818382eadSSubhransu S. Prusty {
174918382eadSSubhransu S. Prusty 	return snd_hda_ext_driver_register(&hdmi_driver);
175018382eadSSubhransu S. Prusty }
175118382eadSSubhransu S. Prusty 
175218382eadSSubhransu S. Prusty static void __exit hdmi_exit(void)
175318382eadSSubhransu S. Prusty {
175418382eadSSubhransu S. Prusty 	snd_hda_ext_driver_unregister(&hdmi_driver);
175518382eadSSubhransu S. Prusty }
175618382eadSSubhransu S. Prusty 
175718382eadSSubhransu S. Prusty module_init(hdmi_init);
175818382eadSSubhransu S. Prusty module_exit(hdmi_exit);
175918382eadSSubhransu S. Prusty 
176018382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2");
176118382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec");
176218382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
176318382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
1764