xref: /openbmc/linux/sound/soc/codecs/hdac_hdmi.c (revision 79f4e922b54771a4d41b1da67caf109ba92ed95a)
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>
2718382eadSSubhransu S. Prusty #include <sound/soc.h>
2818382eadSSubhransu S. Prusty #include <sound/hdaudio_ext.h>
2907f083abSSubhransu S. Prusty #include <sound/hda_i915.h>
302428bca3SSubhransu S. Prusty #include <sound/pcm_drm_eld.h>
3118382eadSSubhransu S. Prusty #include "../../hda/local.h"
3218382eadSSubhransu S. Prusty 
3317a42c45SSubhransu S. Prusty #define NAME_SIZE	32
3417a42c45SSubhransu S. Prusty 
35b0362adbSSubhransu S. Prusty #define AMP_OUT_MUTE		0xb080
36b0362adbSSubhransu S. Prusty #define AMP_OUT_UNMUTE		0xb000
3718382eadSSubhransu S. Prusty #define PIN_OUT			(AC_PINCTL_OUT_EN)
38b0362adbSSubhransu S. Prusty 
3918382eadSSubhransu S. Prusty #define HDA_MAX_CONNECTIONS     32
4018382eadSSubhransu S. Prusty 
41b8a54545SSubhransu S. Prusty #define ELD_MAX_SIZE    256
42b8a54545SSubhransu S. Prusty #define ELD_FIXED_BYTES	20
43b8a54545SSubhransu S. Prusty 
4418382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params {
4518382eadSSubhransu S. Prusty 	unsigned int channels_min;
4618382eadSSubhransu S. Prusty 	unsigned int channels_max;
4718382eadSSubhransu S. Prusty 	u32 rates;
4818382eadSSubhransu S. Prusty 	u64 formats;
4918382eadSSubhransu S. Prusty 	unsigned int maxbps;
5018382eadSSubhransu S. Prusty };
5118382eadSSubhransu S. Prusty 
5218382eadSSubhransu S. Prusty struct hdac_hdmi_cvt {
5315b91447SSubhransu S. Prusty 	struct list_head head;
5418382eadSSubhransu S. Prusty 	hda_nid_t nid;
5518382eadSSubhransu S. Prusty 	struct hdac_hdmi_cvt_params params;
5618382eadSSubhransu S. Prusty };
5718382eadSSubhransu S. Prusty 
58b8a54545SSubhransu S. Prusty struct hdac_hdmi_eld {
59b8a54545SSubhransu S. Prusty 	bool	monitor_present;
60b8a54545SSubhransu S. Prusty 	bool	eld_valid;
61b8a54545SSubhransu S. Prusty 	int	eld_size;
62b8a54545SSubhransu S. Prusty 	char    eld_buffer[ELD_MAX_SIZE];
63b8a54545SSubhransu S. Prusty };
64b8a54545SSubhransu S. Prusty 
6518382eadSSubhransu S. Prusty struct hdac_hdmi_pin {
6615b91447SSubhransu S. Prusty 	struct list_head head;
6718382eadSSubhransu S. Prusty 	hda_nid_t nid;
6818382eadSSubhransu S. Prusty 	int num_mux_nids;
6918382eadSSubhransu S. Prusty 	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
70b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_eld eld;
71b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev;
72b8a54545SSubhransu S. Prusty 	int repoll_count;
73b8a54545SSubhransu S. Prusty 	struct delayed_work work;
7418382eadSSubhransu S. Prusty };
7518382eadSSubhransu S. Prusty 
7618382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map {
7718382eadSSubhransu S. Prusty 	int dai_id;
7815b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
7915b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
8018382eadSSubhransu S. Prusty };
8118382eadSSubhransu S. Prusty 
8218382eadSSubhransu S. Prusty struct hdac_hdmi_priv {
8318382eadSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map dai_map[3];
8415b91447SSubhransu S. Prusty 	struct list_head pin_list;
8515b91447SSubhransu S. Prusty 	struct list_head cvt_list;
8615b91447SSubhransu S. Prusty 	int num_pin;
8715b91447SSubhransu S. Prusty 	int num_cvt;
8818382eadSSubhransu S. Prusty };
8918382eadSSubhransu S. Prusty 
90e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
91e342ac08SSubhransu S. Prusty {
9251b2c425SGeliang Tang 	struct hdac_device *hdac = dev_to_hdac_dev(dev);
93e342ac08SSubhransu S. Prusty 
9451b2c425SGeliang Tang 	return to_ehdac_device(hdac);
95e342ac08SSubhransu S. Prusty }
96e342ac08SSubhransu S. Prusty 
972428bca3SSubhransu S. Prusty static unsigned int sad_format(const u8 *sad)
982428bca3SSubhransu S. Prusty {
992428bca3SSubhransu S. Prusty 	return ((sad[0] >> 0x3) & 0x1f);
1002428bca3SSubhransu S. Prusty }
1012428bca3SSubhransu S. Prusty 
1022428bca3SSubhransu S. Prusty static unsigned int sad_sample_bits_lpcm(const u8 *sad)
1032428bca3SSubhransu S. Prusty {
1042428bca3SSubhransu S. Prusty 	return (sad[2] & 7);
1052428bca3SSubhransu S. Prusty }
1062428bca3SSubhransu S. Prusty 
1072428bca3SSubhransu S. Prusty static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime,
1082428bca3SSubhransu S. Prusty 						void *eld)
1092428bca3SSubhransu S. Prusty {
1102428bca3SSubhransu S. Prusty 	u64 formats = SNDRV_PCM_FMTBIT_S16;
1112428bca3SSubhransu S. Prusty 	int i;
1122428bca3SSubhransu S. Prusty 	const u8 *sad, *eld_buf = eld;
1132428bca3SSubhransu S. Prusty 
1142428bca3SSubhransu S. Prusty 	sad = drm_eld_sad(eld_buf);
1152428bca3SSubhransu S. Prusty 	if (!sad)
1162428bca3SSubhransu S. Prusty 		goto format_constraint;
1172428bca3SSubhransu S. Prusty 
1182428bca3SSubhransu S. Prusty 	for (i = drm_eld_sad_count(eld_buf); i > 0; i--, sad += 3) {
1192428bca3SSubhransu S. Prusty 		if (sad_format(sad) == 1) { /* AUDIO_CODING_TYPE_LPCM */
1202428bca3SSubhransu S. Prusty 
1212428bca3SSubhransu S. Prusty 			/*
1222428bca3SSubhransu S. Prusty 			 * the controller support 20 and 24 bits in 32 bit
1232428bca3SSubhransu S. Prusty 			 * container so we set S32
1242428bca3SSubhransu S. Prusty 			 */
1252428bca3SSubhransu S. Prusty 			if (sad_sample_bits_lpcm(sad) & 0x6)
1262428bca3SSubhransu S. Prusty 				formats |= SNDRV_PCM_FMTBIT_S32;
1272428bca3SSubhransu S. Prusty 		}
1282428bca3SSubhransu S. Prusty 	}
1292428bca3SSubhransu S. Prusty 
1302428bca3SSubhransu S. Prusty format_constraint:
1312428bca3SSubhransu S. Prusty 	return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT,
1322428bca3SSubhransu S. Prusty 				formats);
1332428bca3SSubhransu S. Prusty 
1342428bca3SSubhransu S. Prusty }
1352428bca3SSubhransu S. Prusty 
136b8a54545SSubhransu S. Prusty  /* HDMI ELD routines */
137b8a54545SSubhransu S. Prusty static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec,
138b8a54545SSubhransu S. Prusty 				hda_nid_t nid, int byte_index)
139b8a54545SSubhransu S. Prusty {
140b8a54545SSubhransu S. Prusty 	unsigned int val;
141b8a54545SSubhransu S. Prusty 
142b8a54545SSubhransu S. Prusty 	val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD,
143b8a54545SSubhransu S. Prusty 							byte_index);
144b8a54545SSubhransu S. Prusty 
145b8a54545SSubhransu S. Prusty 	dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n",
146b8a54545SSubhransu S. Prusty 					byte_index, val);
147b8a54545SSubhransu S. Prusty 
148b8a54545SSubhransu S. Prusty 	return val;
149b8a54545SSubhransu S. Prusty }
150b8a54545SSubhransu S. Prusty 
151b8a54545SSubhransu S. Prusty static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid)
152b8a54545SSubhransu S. Prusty {
153b8a54545SSubhransu S. Prusty 	return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
154b8a54545SSubhransu S. Prusty 						 AC_DIPSIZE_ELD_BUF);
155b8a54545SSubhransu S. Prusty }
156b8a54545SSubhransu S. Prusty 
157b8a54545SSubhransu S. Prusty /*
158b8a54545SSubhransu S. Prusty  * This function queries the ELD size and ELD data and fills in the buffer
159b8a54545SSubhransu S. Prusty  * passed by user
160b8a54545SSubhransu S. Prusty  */
161b8a54545SSubhransu S. Prusty static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid,
162b8a54545SSubhransu S. Prusty 			     unsigned char *buf, int *eld_size)
163b8a54545SSubhransu S. Prusty {
164b8a54545SSubhransu S. Prusty 	int i, size, ret = 0;
165b8a54545SSubhransu S. Prusty 
166b8a54545SSubhransu S. Prusty 	/*
167b8a54545SSubhransu S. Prusty 	 * ELD size is initialized to zero in caller function. If no errors and
168b8a54545SSubhransu S. Prusty 	 * ELD is valid, actual eld_size is assigned.
169b8a54545SSubhransu S. Prusty 	 */
170b8a54545SSubhransu S. Prusty 
171b8a54545SSubhransu S. Prusty 	size = hdac_hdmi_get_eld_size(codec, nid);
172b8a54545SSubhransu S. Prusty 	if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
173b8a54545SSubhransu S. Prusty 		dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size);
174b8a54545SSubhransu S. Prusty 		return -ERANGE;
175b8a54545SSubhransu S. Prusty 	}
176b8a54545SSubhransu S. Prusty 
177b8a54545SSubhransu S. Prusty 	/* set ELD buffer */
178b8a54545SSubhransu S. Prusty 	for (i = 0; i < size; i++) {
179b8a54545SSubhransu S. Prusty 		unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i);
180b8a54545SSubhransu S. Prusty 		/*
181b8a54545SSubhransu S. Prusty 		 * Graphics driver might be writing to ELD buffer right now.
182b8a54545SSubhransu S. Prusty 		 * Just abort. The caller will repoll after a while.
183b8a54545SSubhransu S. Prusty 		 */
184b8a54545SSubhransu S. Prusty 		if (!(val & AC_ELDD_ELD_VALID)) {
185b8a54545SSubhransu S. Prusty 			dev_err(&codec->dev,
186b8a54545SSubhransu S. Prusty 				"HDMI: invalid ELD data byte %d\n", i);
187b8a54545SSubhransu S. Prusty 			ret = -EINVAL;
188b8a54545SSubhransu S. Prusty 			goto error;
189b8a54545SSubhransu S. Prusty 		}
190b8a54545SSubhransu S. Prusty 		val &= AC_ELDD_ELD_DATA;
191b8a54545SSubhransu S. Prusty 		/*
192b8a54545SSubhransu S. Prusty 		 * The first byte cannot be zero. This can happen on some DVI
193b8a54545SSubhransu S. Prusty 		 * connections. Some Intel chips may also need some 250ms delay
194b8a54545SSubhransu S. Prusty 		 * to return non-zero ELD data, even when the graphics driver
195b8a54545SSubhransu S. Prusty 		 * correctly writes ELD content before setting ELD_valid bit.
196b8a54545SSubhransu S. Prusty 		 */
197b8a54545SSubhransu S. Prusty 		if (!val && !i) {
198b8a54545SSubhransu S. Prusty 			dev_err(&codec->dev, "HDMI: 0 ELD data\n");
199b8a54545SSubhransu S. Prusty 			ret = -EINVAL;
200b8a54545SSubhransu S. Prusty 			goto error;
201b8a54545SSubhransu S. Prusty 		}
202b8a54545SSubhransu S. Prusty 		buf[i] = val;
203b8a54545SSubhransu S. Prusty 	}
204b8a54545SSubhransu S. Prusty 
205b8a54545SSubhransu S. Prusty 	*eld_size = size;
206b8a54545SSubhransu S. Prusty error:
207b8a54545SSubhransu S. Prusty 	return ret;
208b8a54545SSubhransu S. Prusty }
209b8a54545SSubhransu S. Prusty 
210b0362adbSSubhransu S. Prusty static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
211b0362adbSSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid,
212b0362adbSSubhransu S. Prusty 				u32 stream_tag, int format)
213b0362adbSSubhransu S. Prusty {
214b0362adbSSubhransu S. Prusty 	unsigned int val;
215b0362adbSSubhransu S. Prusty 
216b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
217b0362adbSSubhransu S. Prusty 			cvt_nid, pin_nid, stream_tag, format);
218b0362adbSSubhransu S. Prusty 
219b0362adbSSubhransu S. Prusty 	val = (stream_tag << 4);
220b0362adbSSubhransu S. Prusty 
221b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
222b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, val);
223b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
224b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, format);
225b0362adbSSubhransu S. Prusty 
226b0362adbSSubhransu S. Prusty 	return 0;
227b0362adbSSubhransu S. Prusty }
228b0362adbSSubhransu S. Prusty 
229a657f1d0SSubhransu S. Prusty static void
230a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
231a657f1d0SSubhransu S. Prusty 				int packet_index, int byte_index)
232a657f1d0SSubhransu S. Prusty {
233a657f1d0SSubhransu S. Prusty 	int val;
234a657f1d0SSubhransu S. Prusty 
235a657f1d0SSubhransu S. Prusty 	val = (packet_index << 5) | (byte_index & 0x1f);
236a657f1d0SSubhransu S. Prusty 
237a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
238a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_INDEX, val);
239a657f1d0SSubhransu S. Prusty }
240a657f1d0SSubhransu S. Prusty 
241a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
242a657f1d0SSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid)
243a657f1d0SSubhransu S. Prusty {
244a657f1d0SSubhransu S. Prusty 	uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
245a657f1d0SSubhransu S. Prusty 	struct hdmi_audio_infoframe frame;
246a657f1d0SSubhransu S. Prusty 	u8 *dip = (u8 *)&frame;
247a657f1d0SSubhransu S. Prusty 	int ret;
248a657f1d0SSubhransu S. Prusty 	int i;
249a657f1d0SSubhransu S. Prusty 
250a657f1d0SSubhransu S. Prusty 	hdmi_audio_infoframe_init(&frame);
251a657f1d0SSubhransu S. Prusty 
252a657f1d0SSubhransu S. Prusty 	/* Default stereo for now */
253a657f1d0SSubhransu S. Prusty 	frame.channels = 2;
254a657f1d0SSubhransu S. Prusty 
255a657f1d0SSubhransu S. Prusty 	/* setup channel count */
256a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
257a657f1d0SSubhransu S. Prusty 			    AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1);
258a657f1d0SSubhransu S. Prusty 
259a657f1d0SSubhransu S. Prusty 	ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
260a657f1d0SSubhransu S. Prusty 	if (ret < 0)
261a657f1d0SSubhransu S. Prusty 		return ret;
262a657f1d0SSubhransu S. Prusty 
263a657f1d0SSubhransu S. Prusty 	/* stop infoframe transmission */
264a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
265a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
266a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
267a657f1d0SSubhransu S. Prusty 
268a657f1d0SSubhransu S. Prusty 
269a657f1d0SSubhransu S. Prusty 	/*  Fill infoframe. Index auto-incremented */
270a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
271a657f1d0SSubhransu S. Prusty 	for (i = 0; i < sizeof(frame); i++)
272a657f1d0SSubhransu S. Prusty 		snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
273a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
274a657f1d0SSubhransu S. Prusty 
275a657f1d0SSubhransu S. Prusty 	/* Start infoframe */
276a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
277a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
278a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
279a657f1d0SSubhransu S. Prusty 
280a657f1d0SSubhransu S. Prusty 	return 0;
281a657f1d0SSubhransu S. Prusty }
282a657f1d0SSubhransu S. Prusty 
283b0362adbSSubhransu S. Prusty static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
284b0362adbSSubhransu S. Prusty 		struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
285b0362adbSSubhransu S. Prusty {
286b0362adbSSubhransu S. Prusty 	/* Power up pin widget */
28715b91447SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
28815b91447SSubhransu S. Prusty 						pwr_state))
28915b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
290b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
291b0362adbSSubhransu S. Prusty 
292b0362adbSSubhransu S. Prusty 	/* Power up converter */
29315b91447SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
29415b91447SSubhransu S. Prusty 						pwr_state))
29515b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
296b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
297b0362adbSSubhransu S. Prusty }
298b0362adbSSubhransu S. Prusty 
299b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
300b0362adbSSubhransu S. Prusty 				struct snd_soc_dai *dai)
301b0362adbSSubhransu S. Prusty {
302b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
303b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
304b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
305b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
306a657f1d0SSubhransu S. Prusty 	int ret;
307b0362adbSSubhransu S. Prusty 
308b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
309b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
310b0362adbSSubhransu S. Prusty 		return -ENODEV;
311b0362adbSSubhransu S. Prusty 	}
312b0362adbSSubhransu S. Prusty 
313b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
314b0362adbSSubhransu S. Prusty 
315b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
316b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
317b0362adbSSubhransu S. Prusty 			dd->stream_tag,	dd->format);
318b0362adbSSubhransu S. Prusty 
31915b91447SSubhransu S. Prusty 	ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
32015b91447SSubhransu S. Prusty 						dai_map->pin->nid);
321a657f1d0SSubhransu S. Prusty 	if (ret < 0)
322a657f1d0SSubhransu S. Prusty 		return ret;
323a657f1d0SSubhransu S. Prusty 
32415b91447SSubhransu S. Prusty 	return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
32515b91447SSubhransu S. Prusty 			dai_map->pin->nid, dd->stream_tag, dd->format);
326b0362adbSSubhransu S. Prusty }
327b0362adbSSubhransu S. Prusty 
328b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
329b0362adbSSubhransu S. Prusty 	struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
330b0362adbSSubhransu S. Prusty {
331b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
332b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
333b0362adbSSubhransu S. Prusty 
334b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
335b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
336b0362adbSSubhransu S. Prusty 		return -ENODEV;
337b0362adbSSubhransu S. Prusty 	}
338b0362adbSSubhransu S. Prusty 
339b0362adbSSubhransu S. Prusty 	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
3408d33ab24SSudip Mukherjee 	if (!dd)
3418d33ab24SSudip Mukherjee 		return -ENOMEM;
342b0362adbSSubhransu S. Prusty 	dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
343b0362adbSSubhransu S. Prusty 			params_channels(hparams), params_format(hparams),
344b0362adbSSubhransu S. Prusty 			24, 0);
345b0362adbSSubhransu S. Prusty 
346b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
347b0362adbSSubhransu S. Prusty 
348b0362adbSSubhransu S. Prusty 	return 0;
349b0362adbSSubhransu S. Prusty }
350b0362adbSSubhransu S. Prusty 
351b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
352b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
353b0362adbSSubhransu S. Prusty {
354b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
355b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
356b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
357b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
358b0362adbSSubhransu S. Prusty 
359b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
360b0362adbSSubhransu S. Prusty 
36115b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
362b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, 0);
36315b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
364b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, 0);
365b0362adbSSubhransu S. Prusty 
366b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
367b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, NULL);
368b0362adbSSubhransu S. Prusty 
369b0362adbSSubhransu S. Prusty 	kfree(dd);
370b0362adbSSubhransu S. Prusty 
371b0362adbSSubhransu S. Prusty 	return 0;
372b0362adbSSubhransu S. Prusty }
373b0362adbSSubhransu S. Prusty 
374b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
375b0362adbSSubhransu S. Prusty 			struct snd_soc_dai *dai)
376b0362adbSSubhransu S. Prusty {
377b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
378b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
379b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
3802428bca3SSubhransu S. Prusty 	int ret;
381b0362adbSSubhransu S. Prusty 
382b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
383b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
384b0362adbSSubhransu S. Prusty 		return -ENODEV;
385b0362adbSSubhransu S. Prusty 	}
386b0362adbSSubhransu S. Prusty 
387b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
388b0362adbSSubhransu S. Prusty 
389b8a54545SSubhransu S. Prusty 	if ((!dai_map->pin->eld.monitor_present) ||
390b8a54545SSubhransu S. Prusty 			(!dai_map->pin->eld.eld_valid)) {
391b0362adbSSubhransu S. Prusty 
392b8a54545SSubhransu S. Prusty 		dev_err(&hdac->hdac.dev,
393b8a54545SSubhransu S. Prusty 				"Failed: montior present? %d ELD valid?: %d\n",
394b8a54545SSubhransu S. Prusty 				dai_map->pin->eld.monitor_present,
395b8a54545SSubhransu S. Prusty 				dai_map->pin->eld.eld_valid);
396b8a54545SSubhransu S. Prusty 
397b0362adbSSubhransu S. Prusty 		return -ENODEV;
398b0362adbSSubhransu S. Prusty 	}
399b0362adbSSubhransu S. Prusty 
400b0362adbSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
401b0362adbSSubhransu S. Prusty 
40215b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
403b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
404b0362adbSSubhransu S. Prusty 
4052428bca3SSubhransu S. Prusty 	ret = hdac_hdmi_eld_limit_formats(substream->runtime,
4062428bca3SSubhransu S. Prusty 				dai_map->pin->eld.eld_buffer);
4072428bca3SSubhransu S. Prusty 	if (ret < 0)
4082428bca3SSubhransu S. Prusty 		return ret;
409b0362adbSSubhransu S. Prusty 
4102428bca3SSubhransu S. Prusty 	return snd_pcm_hw_constraint_eld(substream->runtime,
4112428bca3SSubhransu S. Prusty 				dai_map->pin->eld.eld_buffer);
412b0362adbSSubhransu S. Prusty }
413b0362adbSSubhransu S. Prusty 
414b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
415b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
416b0362adbSSubhransu S. Prusty {
417b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
418b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
419b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
420b0362adbSSubhransu S. Prusty 
421b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
422b0362adbSSubhransu S. Prusty 
423b0362adbSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
424b0362adbSSubhransu S. Prusty 
42515b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
426b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
427b0362adbSSubhransu S. Prusty }
428b0362adbSSubhransu S. Prusty 
42918382eadSSubhransu S. Prusty static int
43018382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
43118382eadSSubhransu S. Prusty {
43218382eadSSubhransu S. Prusty 	int err;
43318382eadSSubhransu S. Prusty 
43418382eadSSubhransu S. Prusty 	/* Only stereo supported as of now */
43518382eadSSubhransu S. Prusty 	cvt->params.channels_min = cvt->params.channels_max = 2;
43618382eadSSubhransu S. Prusty 
43718382eadSSubhransu S. Prusty 	err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
43818382eadSSubhransu S. Prusty 			&cvt->params.rates,
43918382eadSSubhransu S. Prusty 			&cvt->params.formats,
44018382eadSSubhransu S. Prusty 			&cvt->params.maxbps);
44118382eadSSubhransu S. Prusty 	if (err < 0)
44218382eadSSubhransu S. Prusty 		dev_err(&hdac->dev,
44318382eadSSubhransu S. Prusty 			"Failed to query pcm params for nid %d: %d\n",
44418382eadSSubhransu S. Prusty 			cvt->nid, err);
44518382eadSSubhransu S. Prusty 
44618382eadSSubhransu S. Prusty 	return err;
44718382eadSSubhransu S. Prusty }
44818382eadSSubhransu S. Prusty 
449*79f4e922SSubhransu S. Prusty static int hdac_hdmi_fill_widget_info(struct device *dev,
450*79f4e922SSubhransu S. Prusty 				struct snd_soc_dapm_widget *w,
451*79f4e922SSubhransu S. Prusty 				enum snd_soc_dapm_type id, void *priv,
452*79f4e922SSubhransu S. Prusty 				const char *wname, const char *stream,
453*79f4e922SSubhransu S. Prusty 				struct snd_kcontrol_new *wc, int numkc)
45418382eadSSubhransu S. Prusty {
45518382eadSSubhransu S. Prusty 	w->id = id;
456*79f4e922SSubhransu S. Prusty 	w->name = devm_kstrdup(dev, wname, GFP_KERNEL);
457*79f4e922SSubhransu S. Prusty 	if (!w->name)
458*79f4e922SSubhransu S. Prusty 		return -ENOMEM;
459*79f4e922SSubhransu S. Prusty 
46018382eadSSubhransu S. Prusty 	w->sname = stream;
46118382eadSSubhransu S. Prusty 	w->reg = SND_SOC_NOPM;
46218382eadSSubhransu S. Prusty 	w->shift = 0;
463*79f4e922SSubhransu S. Prusty 	w->kcontrol_news = wc;
464*79f4e922SSubhransu S. Prusty 	w->num_kcontrols = numkc;
465*79f4e922SSubhransu S. Prusty 	w->priv = priv;
466*79f4e922SSubhransu S. Prusty 
467*79f4e922SSubhransu S. Prusty 	return 0;
46818382eadSSubhransu S. Prusty }
46918382eadSSubhransu S. Prusty 
47018382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
471*79f4e922SSubhransu S. Prusty 		const char *sink, const char *control, const char *src,
472*79f4e922SSubhransu S. Prusty 		int (*handler)(struct snd_soc_dapm_widget *src,
473*79f4e922SSubhransu S. Prusty 			struct snd_soc_dapm_widget *sink))
47418382eadSSubhransu S. Prusty {
47518382eadSSubhransu S. Prusty 	route->sink = sink;
47618382eadSSubhransu S. Prusty 	route->source = src;
47718382eadSSubhransu S. Prusty 	route->control = control;
478*79f4e922SSubhransu S. Prusty 	route->connected = handler;
47918382eadSSubhransu S. Prusty }
48018382eadSSubhransu S. Prusty 
481*79f4e922SSubhransu S. Prusty /*
482*79f4e922SSubhransu S. Prusty  * Ideally the Mux inputs should be based on the num_muxs enumerated, but
483*79f4e922SSubhransu S. Prusty  * the display driver seem to be programming the connection list for the pin
484*79f4e922SSubhransu S. Prusty  * widget runtime.
485*79f4e922SSubhransu S. Prusty  *
486*79f4e922SSubhransu S. Prusty  * So programming all the possible inputs for the mux, the user has to take
487*79f4e922SSubhransu S. Prusty  * care of selecting the right one and leaving all other inputs selected to
488*79f4e922SSubhransu S. Prusty  * "NONE"
489*79f4e922SSubhransu S. Prusty  */
490*79f4e922SSubhransu S. Prusty static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev,
491*79f4e922SSubhransu S. Prusty 				struct hdac_hdmi_pin *pin,
492*79f4e922SSubhransu S. Prusty 				struct snd_soc_dapm_widget *widget,
493*79f4e922SSubhransu S. Prusty 				const char *widget_name)
49418382eadSSubhransu S. Prusty {
495*79f4e922SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
496*79f4e922SSubhransu S. Prusty 	struct snd_kcontrol_new *kc;
497*79f4e922SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
498*79f4e922SSubhransu S. Prusty 	struct soc_enum *se;
499*79f4e922SSubhransu S. Prusty 	char kc_name[NAME_SIZE];
500*79f4e922SSubhransu S. Prusty 	char mux_items[NAME_SIZE];
501*79f4e922SSubhransu S. Prusty 	/* To hold inputs to the Pin mux */
502*79f4e922SSubhransu S. Prusty 	char *items[HDA_MAX_CONNECTIONS];
503*79f4e922SSubhransu S. Prusty 	int i = 0;
504*79f4e922SSubhransu S. Prusty 	int num_items = hdmi->num_cvt + 1;
50518382eadSSubhransu S. Prusty 
506*79f4e922SSubhransu S. Prusty 	kc = devm_kzalloc(&edev->hdac.dev, sizeof(*kc), GFP_KERNEL);
507*79f4e922SSubhransu S. Prusty 	if (!kc)
508*79f4e922SSubhransu S. Prusty 		return -ENOMEM;
50918382eadSSubhransu S. Prusty 
510*79f4e922SSubhransu S. Prusty 	se = devm_kzalloc(&edev->hdac.dev, sizeof(*se), GFP_KERNEL);
511*79f4e922SSubhransu S. Prusty 	if (!se)
512*79f4e922SSubhransu S. Prusty 		return -ENOMEM;
51318382eadSSubhransu S. Prusty 
514*79f4e922SSubhransu S. Prusty 	sprintf(kc_name, "Pin %d Input", pin->nid);
515*79f4e922SSubhransu S. Prusty 	kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL);
516*79f4e922SSubhransu S. Prusty 	if (!kc->name)
517*79f4e922SSubhransu S. Prusty 		return -ENOMEM;
51818382eadSSubhransu S. Prusty 
519*79f4e922SSubhransu S. Prusty 	kc->private_value = (long)se;
520*79f4e922SSubhransu S. Prusty 	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
521*79f4e922SSubhransu S. Prusty 	kc->access = 0;
522*79f4e922SSubhransu S. Prusty 	kc->info = snd_soc_info_enum_double;
523*79f4e922SSubhransu S. Prusty 	kc->put = snd_soc_dapm_put_enum_double;
524*79f4e922SSubhransu S. Prusty 	kc->get = snd_soc_dapm_get_enum_double;
525*79f4e922SSubhransu S. Prusty 
526*79f4e922SSubhransu S. Prusty 	se->reg = SND_SOC_NOPM;
527*79f4e922SSubhransu S. Prusty 
528*79f4e922SSubhransu S. Prusty 	/* enum texts: ["NONE", "cvt #", "cvt #", ...] */
529*79f4e922SSubhransu S. Prusty 	se->items = num_items;
530*79f4e922SSubhransu S. Prusty 	se->mask = roundup_pow_of_two(se->items) - 1;
531*79f4e922SSubhransu S. Prusty 
532*79f4e922SSubhransu S. Prusty 	sprintf(mux_items, "NONE");
533*79f4e922SSubhransu S. Prusty 	items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL);
534*79f4e922SSubhransu S. Prusty 	if (!items[i])
535*79f4e922SSubhransu S. Prusty 		return -ENOMEM;
536*79f4e922SSubhransu S. Prusty 
537*79f4e922SSubhransu S. Prusty 	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
538*79f4e922SSubhransu S. Prusty 		i++;
539*79f4e922SSubhransu S. Prusty 		sprintf(mux_items, "cvt %d", cvt->nid);
540*79f4e922SSubhransu S. Prusty 		items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL);
541*79f4e922SSubhransu S. Prusty 		if (!items[i])
542*79f4e922SSubhransu S. Prusty 			return -ENOMEM;
543*79f4e922SSubhransu S. Prusty 	}
544*79f4e922SSubhransu S. Prusty 
545*79f4e922SSubhransu S. Prusty 	se->texts = devm_kmemdup(&edev->hdac.dev, items,
546*79f4e922SSubhransu S. Prusty 			(num_items  * sizeof(char *)), GFP_KERNEL);
547*79f4e922SSubhransu S. Prusty 	if (!se->texts)
548*79f4e922SSubhransu S. Prusty 		return -ENOMEM;
549*79f4e922SSubhransu S. Prusty 
550*79f4e922SSubhransu S. Prusty 	return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget,
551*79f4e922SSubhransu S. Prusty 			snd_soc_dapm_mux, &pin->nid, widget_name,
552*79f4e922SSubhransu S. Prusty 			NULL, kc, 1);
553*79f4e922SSubhransu S. Prusty }
554*79f4e922SSubhransu S. Prusty 
555*79f4e922SSubhransu S. Prusty /* Add cvt <- input <- mux route map */
556*79f4e922SSubhransu S. Prusty static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev,
557*79f4e922SSubhransu S. Prusty 			struct snd_soc_dapm_widget *widgets,
558*79f4e922SSubhransu S. Prusty 			struct snd_soc_dapm_route *route, int rindex)
559*79f4e922SSubhransu S. Prusty {
560*79f4e922SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
561*79f4e922SSubhransu S. Prusty 	const struct snd_kcontrol_new *kc;
562*79f4e922SSubhransu S. Prusty 	struct soc_enum *se;
563*79f4e922SSubhransu S. Prusty 	int mux_index = hdmi->num_cvt + hdmi->num_pin;
564*79f4e922SSubhransu S. Prusty 	int i, j;
565*79f4e922SSubhransu S. Prusty 
566*79f4e922SSubhransu S. Prusty 	for (i = 0; i < hdmi->num_pin; i++) {
567*79f4e922SSubhransu S. Prusty 		kc = widgets[mux_index].kcontrol_news;
568*79f4e922SSubhransu S. Prusty 		se = (struct soc_enum *)kc->private_value;
569*79f4e922SSubhransu S. Prusty 		for (j = 0; j < hdmi->num_cvt; j++) {
570*79f4e922SSubhransu S. Prusty 			hdac_hdmi_fill_route(&route[rindex],
571*79f4e922SSubhransu S. Prusty 					widgets[mux_index].name,
572*79f4e922SSubhransu S. Prusty 					se->texts[j + 1],
573*79f4e922SSubhransu S. Prusty 					widgets[j].name, NULL);
574*79f4e922SSubhransu S. Prusty 
575*79f4e922SSubhransu S. Prusty 			rindex++;
576*79f4e922SSubhransu S. Prusty 		}
577*79f4e922SSubhransu S. Prusty 
578*79f4e922SSubhransu S. Prusty 		mux_index++;
579*79f4e922SSubhransu S. Prusty 	}
580*79f4e922SSubhransu S. Prusty }
581*79f4e922SSubhransu S. Prusty 
582*79f4e922SSubhransu S. Prusty /*
583*79f4e922SSubhransu S. Prusty  * Widgets are added in the below sequence
584*79f4e922SSubhransu S. Prusty  *	Converter widgets for num converters enumerated
585*79f4e922SSubhransu S. Prusty  *	Pin widgets for num pins enumerated
586*79f4e922SSubhransu S. Prusty  *	Pin mux widgets to represent connenction list of pin widget
587*79f4e922SSubhransu S. Prusty  *
588*79f4e922SSubhransu S. Prusty  * Total widgets elements = num_cvt + num_pin + num_pin;
589*79f4e922SSubhransu S. Prusty  *
590*79f4e922SSubhransu S. Prusty  * Routes are added as below:
591*79f4e922SSubhransu S. Prusty  *	pin mux -> pin (based on num_pins)
592*79f4e922SSubhransu S. Prusty  *	cvt -> "Input sel control" -> pin_mux
593*79f4e922SSubhransu S. Prusty  *
594*79f4e922SSubhransu S. Prusty  * Total route elements:
595*79f4e922SSubhransu S. Prusty  *	num_pins + (pin_muxes * num_cvt)
596*79f4e922SSubhransu S. Prusty  */
597*79f4e922SSubhransu S. Prusty static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
598*79f4e922SSubhransu S. Prusty {
599*79f4e922SSubhransu S. Prusty 	struct snd_soc_dapm_widget *widgets;
600*79f4e922SSubhransu S. Prusty 	struct snd_soc_dapm_route *route;
601*79f4e922SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
602*79f4e922SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
603*79f4e922SSubhransu S. Prusty 	struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv;
604*79f4e922SSubhransu S. Prusty 	char widget_name[NAME_SIZE];
605*79f4e922SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
606*79f4e922SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
607*79f4e922SSubhransu S. Prusty 	int ret, i = 0, num_routes = 0;
608*79f4e922SSubhransu S. Prusty 
609*79f4e922SSubhransu S. Prusty 	if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
610*79f4e922SSubhransu S. Prusty 		return -EINVAL;
611*79f4e922SSubhransu S. Prusty 
612*79f4e922SSubhransu S. Prusty 	widgets = devm_kzalloc(dapm->dev,
613*79f4e922SSubhransu S. Prusty 		(sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)),
614*79f4e922SSubhransu S. Prusty 		GFP_KERNEL);
615*79f4e922SSubhransu S. Prusty 
616*79f4e922SSubhransu S. Prusty 	if (!widgets)
617*79f4e922SSubhransu S. Prusty 		return -ENOMEM;
618*79f4e922SSubhransu S. Prusty 
619*79f4e922SSubhransu S. Prusty 	/* DAPM widgets to represent each converter widget */
620*79f4e922SSubhransu S. Prusty 	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
621*79f4e922SSubhransu S. Prusty 		sprintf(widget_name, "Converter %d", cvt->nid);
622*79f4e922SSubhransu S. Prusty 		ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
623*79f4e922SSubhransu S. Prusty 			snd_soc_dapm_aif_in, &cvt->nid,
624*79f4e922SSubhransu S. Prusty 			widget_name, dai_drv[i].playback.stream_name, NULL, 0);
625*79f4e922SSubhransu S. Prusty 		if (ret < 0)
626*79f4e922SSubhransu S. Prusty 			return ret;
627*79f4e922SSubhransu S. Prusty 		i++;
628*79f4e922SSubhransu S. Prusty 	}
629*79f4e922SSubhransu S. Prusty 
630*79f4e922SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
631*79f4e922SSubhransu S. Prusty 		sprintf(widget_name, "hif%d Output", pin->nid);
632*79f4e922SSubhransu S. Prusty 		ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
633*79f4e922SSubhransu S. Prusty 				snd_soc_dapm_output, &pin->nid,
634*79f4e922SSubhransu S. Prusty 				widget_name, NULL, NULL, 0);
635*79f4e922SSubhransu S. Prusty 		if (ret < 0)
636*79f4e922SSubhransu S. Prusty 			return ret;
637*79f4e922SSubhransu S. Prusty 		i++;
638*79f4e922SSubhransu S. Prusty 	}
639*79f4e922SSubhransu S. Prusty 
640*79f4e922SSubhransu S. Prusty 	/* DAPM widgets to represent the connection list to pin widget */
641*79f4e922SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
642*79f4e922SSubhransu S. Prusty 		sprintf(widget_name, "Pin %d Mux", pin->nid);
643*79f4e922SSubhransu S. Prusty 		ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i],
644*79f4e922SSubhransu S. Prusty 							widget_name);
645*79f4e922SSubhransu S. Prusty 		if (ret < 0)
646*79f4e922SSubhransu S. Prusty 			return ret;
647*79f4e922SSubhransu S. Prusty 		i++;
648*79f4e922SSubhransu S. Prusty 
649*79f4e922SSubhransu S. Prusty 		/* For cvt to pin_mux mapping */
650*79f4e922SSubhransu S. Prusty 		num_routes += hdmi->num_cvt;
651*79f4e922SSubhransu S. Prusty 
652*79f4e922SSubhransu S. Prusty 		/* For pin_mux to pin mapping */
653*79f4e922SSubhransu S. Prusty 		num_routes++;
654*79f4e922SSubhransu S. Prusty 	}
655*79f4e922SSubhransu S. Prusty 
656*79f4e922SSubhransu S. Prusty 	route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes),
657*79f4e922SSubhransu S. Prusty 							GFP_KERNEL);
658*79f4e922SSubhransu S. Prusty 	if (!route)
659*79f4e922SSubhransu S. Prusty 		return -ENOMEM;
660*79f4e922SSubhransu S. Prusty 
661*79f4e922SSubhransu S. Prusty 	i = 0;
662*79f4e922SSubhransu S. Prusty 	/* Add pin <- NULL <- mux route map */
663*79f4e922SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
664*79f4e922SSubhransu S. Prusty 		int sink_index = i + hdmi->num_cvt;
665*79f4e922SSubhransu S. Prusty 		int src_index = sink_index + hdmi->num_pin;
666*79f4e922SSubhransu S. Prusty 
667*79f4e922SSubhransu S. Prusty 		hdac_hdmi_fill_route(&route[i],
668*79f4e922SSubhransu S. Prusty 				widgets[sink_index].name, NULL,
669*79f4e922SSubhransu S. Prusty 				widgets[src_index].name, NULL);
670*79f4e922SSubhransu S. Prusty 		i++;
671*79f4e922SSubhransu S. Prusty 
672*79f4e922SSubhransu S. Prusty 	}
673*79f4e922SSubhransu S. Prusty 
674*79f4e922SSubhransu S. Prusty 	hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i);
675*79f4e922SSubhransu S. Prusty 
676*79f4e922SSubhransu S. Prusty 	snd_soc_dapm_new_controls(dapm, widgets,
677*79f4e922SSubhransu S. Prusty 		((2 * hdmi->num_pin) + hdmi->num_cvt));
678*79f4e922SSubhransu S. Prusty 
679*79f4e922SSubhransu S. Prusty 	snd_soc_dapm_add_routes(dapm, route, num_routes);
680*79f4e922SSubhransu S. Prusty 	snd_soc_dapm_new_widgets(dapm->card);
681*79f4e922SSubhransu S. Prusty 
682*79f4e922SSubhransu S. Prusty 	return 0;
683*79f4e922SSubhransu S. Prusty 
68418382eadSSubhransu S. Prusty }
68518382eadSSubhransu S. Prusty 
68615b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
68718382eadSSubhransu S. Prusty {
68815b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
68915b91447SSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
69015b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
69115b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
69218382eadSSubhransu S. Prusty 
69315b91447SSubhransu S. Prusty 	if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
69415b91447SSubhransu S. Prusty 		return -EINVAL;
69518382eadSSubhransu S. Prusty 
69615b91447SSubhransu S. Prusty 	/*
69715b91447SSubhransu S. Prusty 	 * Currently on board only 1 pin and 1 converter is enabled for
69815b91447SSubhransu S. Prusty 	 * simplification, more will be added eventually
69915b91447SSubhransu S. Prusty 	 * So using fixed map for dai_id:pin:cvt
70015b91447SSubhransu S. Prusty 	 */
70115b91447SSubhransu S. Prusty 	cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
70215b91447SSubhransu S. Prusty 	pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
70318382eadSSubhransu S. Prusty 
70415b91447SSubhransu S. Prusty 	dai_map->dai_id = 0;
70515b91447SSubhransu S. Prusty 	dai_map->pin = pin;
70615b91447SSubhransu S. Prusty 
70715b91447SSubhransu S. Prusty 	dai_map->cvt = cvt;
70818382eadSSubhransu S. Prusty 
70918382eadSSubhransu S. Prusty 	/* Enable out path for this pin widget */
71015b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
71118382eadSSubhransu S. Prusty 			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
71218382eadSSubhransu S. Prusty 
71318382eadSSubhransu S. Prusty 	/* Enable transmission */
71415b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
71518382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_1, 1);
71618382eadSSubhransu S. Prusty 
71718382eadSSubhransu S. Prusty 	/* Category Code (CC) to zero */
71815b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
71918382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_2, 0);
72018382eadSSubhransu S. Prusty 
72115b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
72218382eadSSubhransu S. Prusty 			AC_VERB_SET_CONNECT_SEL, 0);
72318382eadSSubhransu S. Prusty 
72415b91447SSubhransu S. Prusty 	return 0;
72515b91447SSubhransu S. Prusty }
72615b91447SSubhransu S. Prusty 
72715b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
72815b91447SSubhransu S. Prusty {
72915b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
73015b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
73115b91447SSubhransu S. Prusty 
73215b91447SSubhransu S. Prusty 	cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
73315b91447SSubhransu S. Prusty 	if (!cvt)
73415b91447SSubhransu S. Prusty 		return -ENOMEM;
73515b91447SSubhransu S. Prusty 
73615b91447SSubhransu S. Prusty 	cvt->nid = nid;
73715b91447SSubhransu S. Prusty 
73815b91447SSubhransu S. Prusty 	list_add_tail(&cvt->head, &hdmi->cvt_list);
73915b91447SSubhransu S. Prusty 	hdmi->num_cvt++;
74015b91447SSubhransu S. Prusty 
74115b91447SSubhransu S. Prusty 	return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
74215b91447SSubhransu S. Prusty }
74315b91447SSubhransu S. Prusty 
744b8a54545SSubhransu S. Prusty static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
745b8a54545SSubhransu S. Prusty {
746b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev = pin->edev;
747b8a54545SSubhransu S. Prusty 	int val;
748b8a54545SSubhransu S. Prusty 
749b8a54545SSubhransu S. Prusty 	if (!edev)
750b8a54545SSubhransu S. Prusty 		return;
751b8a54545SSubhransu S. Prusty 
752b8a54545SSubhransu S. Prusty 	pin->repoll_count = repoll;
753b8a54545SSubhransu S. Prusty 
754b8a54545SSubhransu S. Prusty 	pm_runtime_get_sync(&edev->hdac.dev);
755b8a54545SSubhransu S. Prusty 	val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0,
756b8a54545SSubhransu S. Prusty 					AC_VERB_GET_PIN_SENSE, 0);
757b8a54545SSubhransu S. Prusty 
758b8a54545SSubhransu S. Prusty 	dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n",
759b8a54545SSubhransu S. Prusty 						val, pin->nid);
760b8a54545SSubhransu S. Prusty 
761b8a54545SSubhransu S. Prusty 	pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE);
762b8a54545SSubhransu S. Prusty 	pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV);
763b8a54545SSubhransu S. Prusty 
764b8a54545SSubhransu S. Prusty 	if (!pin->eld.monitor_present || !pin->eld.eld_valid) {
765b8a54545SSubhransu S. Prusty 
766b8a54545SSubhransu S. Prusty 		dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n",
767b8a54545SSubhransu S. Prusty 						__func__, pin->nid);
768b8a54545SSubhransu S. Prusty 		goto put_hdac_device;
769b8a54545SSubhransu S. Prusty 	}
770b8a54545SSubhransu S. Prusty 
771b8a54545SSubhransu S. Prusty 	if (pin->eld.monitor_present && pin->eld.eld_valid) {
772b8a54545SSubhransu S. Prusty 		/* TODO: use i915 component for reading ELD later */
773b8a54545SSubhransu S. Prusty 		if (hdac_hdmi_get_eld(&edev->hdac, pin->nid,
774b8a54545SSubhransu S. Prusty 				pin->eld.eld_buffer,
775b8a54545SSubhransu S. Prusty 				&pin->eld.eld_size) == 0) {
776b8a54545SSubhransu S. Prusty 
777b8a54545SSubhransu S. Prusty 			print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET,
778b8a54545SSubhransu S. Prusty 					pin->eld.eld_buffer, pin->eld.eld_size);
779b8a54545SSubhransu S. Prusty 		} else {
780b8a54545SSubhransu S. Prusty 			pin->eld.monitor_present = false;
781b8a54545SSubhransu S. Prusty 			pin->eld.eld_valid = false;
782b8a54545SSubhransu S. Prusty 		}
783b8a54545SSubhransu S. Prusty 	}
784b8a54545SSubhransu S. Prusty 
785b8a54545SSubhransu S. Prusty 	/*
786b8a54545SSubhransu S. Prusty 	 * Sometimes the pin_sense may present invalid monitor
787b8a54545SSubhransu S. Prusty 	 * present and eld_valid. If ELD data is not valid, loop few
788b8a54545SSubhransu S. Prusty 	 * more times to get correct pin sense and valid ELD.
789b8a54545SSubhransu S. Prusty 	 */
790b8a54545SSubhransu S. Prusty 	if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll)
791b8a54545SSubhransu S. Prusty 		schedule_delayed_work(&pin->work, msecs_to_jiffies(300));
792b8a54545SSubhransu S. Prusty 
793b8a54545SSubhransu S. Prusty put_hdac_device:
794b8a54545SSubhransu S. Prusty 	pm_runtime_put_sync(&edev->hdac.dev);
795b8a54545SSubhransu S. Prusty }
796b8a54545SSubhransu S. Prusty 
797b8a54545SSubhransu S. Prusty static void hdac_hdmi_repoll_eld(struct work_struct *work)
798b8a54545SSubhransu S. Prusty {
799b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin =
800b8a54545SSubhransu S. Prusty 		container_of(to_delayed_work(work), struct hdac_hdmi_pin, work);
801b8a54545SSubhransu S. Prusty 
802b8a54545SSubhransu S. Prusty 	/* picked from legacy HDA driver */
803b8a54545SSubhransu S. Prusty 	if (pin->repoll_count++ > 6)
804b8a54545SSubhransu S. Prusty 		pin->repoll_count = 0;
805b8a54545SSubhransu S. Prusty 
806b8a54545SSubhransu S. Prusty 	hdac_hdmi_present_sense(pin, pin->repoll_count);
807b8a54545SSubhransu S. Prusty }
808b8a54545SSubhransu S. Prusty 
80915b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
81015b91447SSubhransu S. Prusty {
81115b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
81215b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
81315b91447SSubhransu S. Prusty 
81415b91447SSubhransu S. Prusty 	pin = kzalloc(sizeof(*pin), GFP_KERNEL);
81515b91447SSubhransu S. Prusty 	if (!pin)
81615b91447SSubhransu S. Prusty 		return -ENOMEM;
81715b91447SSubhransu S. Prusty 
81815b91447SSubhransu S. Prusty 	pin->nid = nid;
81915b91447SSubhransu S. Prusty 
82015b91447SSubhransu S. Prusty 	list_add_tail(&pin->head, &hdmi->pin_list);
82115b91447SSubhransu S. Prusty 	hdmi->num_pin++;
82215b91447SSubhransu S. Prusty 
823b8a54545SSubhransu S. Prusty 	pin->edev = edev;
824b8a54545SSubhransu S. Prusty 	INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
825b8a54545SSubhransu S. Prusty 
82615b91447SSubhransu S. Prusty 	return 0;
82718382eadSSubhransu S. Prusty }
82818382eadSSubhransu S. Prusty 
829211caab7SSubhransu S. Prusty #define INTEL_VENDOR_NID 0x08
830211caab7SSubhransu S. Prusty #define INTEL_GET_VENDOR_VERB 0xf81
831211caab7SSubhransu S. Prusty #define INTEL_SET_VENDOR_VERB 0x781
832211caab7SSubhransu S. Prusty #define INTEL_EN_DP12			0x02 /* enable DP 1.2 features */
833211caab7SSubhransu S. Prusty #define INTEL_EN_ALL_PIN_CVTS	0x01 /* enable 2nd & 3rd pins and convertors */
834211caab7SSubhransu S. Prusty 
835211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
836211caab7SSubhransu S. Prusty {
837211caab7SSubhransu S. Prusty 	unsigned int vendor_param;
838211caab7SSubhransu S. Prusty 
839211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
840211caab7SSubhransu S. Prusty 				INTEL_GET_VENDOR_VERB, 0);
841211caab7SSubhransu S. Prusty 	if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
842211caab7SSubhransu S. Prusty 		return;
843211caab7SSubhransu S. Prusty 
844211caab7SSubhransu S. Prusty 	vendor_param |= INTEL_EN_ALL_PIN_CVTS;
845211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
846211caab7SSubhransu S. Prusty 				INTEL_SET_VENDOR_VERB, vendor_param);
847211caab7SSubhransu S. Prusty 	if (vendor_param == -1)
848211caab7SSubhransu S. Prusty 		return;
849211caab7SSubhransu S. Prusty }
850211caab7SSubhransu S. Prusty 
851211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
852211caab7SSubhransu S. Prusty {
853211caab7SSubhransu S. Prusty 	unsigned int vendor_param;
854211caab7SSubhransu S. Prusty 
855211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
856211caab7SSubhransu S. Prusty 				INTEL_GET_VENDOR_VERB, 0);
857211caab7SSubhransu S. Prusty 	if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
858211caab7SSubhransu S. Prusty 		return;
859211caab7SSubhransu S. Prusty 
860211caab7SSubhransu S. Prusty 	/* enable DP1.2 mode */
861211caab7SSubhransu S. Prusty 	vendor_param |= INTEL_EN_DP12;
862211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
863211caab7SSubhransu S. Prusty 				INTEL_SET_VENDOR_VERB, vendor_param);
864211caab7SSubhransu S. Prusty 	if (vendor_param == -1)
865211caab7SSubhransu S. Prusty 		return;
866211caab7SSubhransu S. Prusty 
867211caab7SSubhransu S. Prusty }
868211caab7SSubhransu S. Prusty 
86917a42c45SSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = {
87017a42c45SSubhransu S. Prusty 	.startup = hdac_hdmi_pcm_open,
87117a42c45SSubhransu S. Prusty 	.shutdown = hdac_hdmi_pcm_close,
87217a42c45SSubhransu S. Prusty 	.hw_params = hdac_hdmi_set_hw_params,
87317a42c45SSubhransu S. Prusty 	.prepare = hdac_hdmi_playback_prepare,
87417a42c45SSubhransu S. Prusty 	.hw_free = hdac_hdmi_playback_cleanup,
87517a42c45SSubhransu S. Prusty };
87617a42c45SSubhransu S. Prusty 
87717a42c45SSubhransu S. Prusty /*
87817a42c45SSubhransu S. Prusty  * Each converter can support a stream independently. So a dai is created
87917a42c45SSubhransu S. Prusty  * based on the number of converter queried.
88017a42c45SSubhransu S. Prusty  */
88117a42c45SSubhransu S. Prusty static int hdac_hdmi_create_dais(struct hdac_device *hdac,
88217a42c45SSubhransu S. Prusty 		struct snd_soc_dai_driver **dais,
88317a42c45SSubhransu S. Prusty 		struct hdac_hdmi_priv *hdmi, int num_dais)
88417a42c45SSubhransu S. Prusty {
88517a42c45SSubhransu S. Prusty 	struct snd_soc_dai_driver *hdmi_dais;
88617a42c45SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
88717a42c45SSubhransu S. Prusty 	char name[NAME_SIZE], dai_name[NAME_SIZE];
88817a42c45SSubhransu S. Prusty 	int i = 0;
88917a42c45SSubhransu S. Prusty 	u32 rates, bps;
89017a42c45SSubhransu S. Prusty 	unsigned int rate_max = 384000, rate_min = 8000;
89117a42c45SSubhransu S. Prusty 	u64 formats;
89217a42c45SSubhransu S. Prusty 	int ret;
89317a42c45SSubhransu S. Prusty 
89417a42c45SSubhransu S. Prusty 	hdmi_dais = devm_kzalloc(&hdac->dev,
89517a42c45SSubhransu S. Prusty 			(sizeof(*hdmi_dais) * num_dais),
89617a42c45SSubhransu S. Prusty 			GFP_KERNEL);
89717a42c45SSubhransu S. Prusty 	if (!hdmi_dais)
89817a42c45SSubhransu S. Prusty 		return -ENOMEM;
89917a42c45SSubhransu S. Prusty 
90017a42c45SSubhransu S. Prusty 	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
90117a42c45SSubhransu S. Prusty 		ret = snd_hdac_query_supported_pcm(hdac, cvt->nid,
90217a42c45SSubhransu S. Prusty 					&rates,	&formats, &bps);
90317a42c45SSubhransu S. Prusty 		if (ret)
90417a42c45SSubhransu S. Prusty 			return ret;
90517a42c45SSubhransu S. Prusty 
90617a42c45SSubhransu S. Prusty 		sprintf(dai_name, "intel-hdmi-hifi%d", i+1);
90717a42c45SSubhransu S. Prusty 		hdmi_dais[i].name = devm_kstrdup(&hdac->dev,
90817a42c45SSubhransu S. Prusty 					dai_name, GFP_KERNEL);
90917a42c45SSubhransu S. Prusty 
91017a42c45SSubhransu S. Prusty 		if (!hdmi_dais[i].name)
91117a42c45SSubhransu S. Prusty 			return -ENOMEM;
91217a42c45SSubhransu S. Prusty 
91317a42c45SSubhransu S. Prusty 		snprintf(name, sizeof(name), "hifi%d", i+1);
91417a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.stream_name =
91517a42c45SSubhransu S. Prusty 				devm_kstrdup(&hdac->dev, name, GFP_KERNEL);
91617a42c45SSubhransu S. Prusty 		if (!hdmi_dais[i].playback.stream_name)
91717a42c45SSubhransu S. Prusty 			return -ENOMEM;
91817a42c45SSubhransu S. Prusty 
91917a42c45SSubhransu S. Prusty 		/*
92017a42c45SSubhransu S. Prusty 		 * Set caps based on capability queried from the converter.
92117a42c45SSubhransu S. Prusty 		 * It will be constrained runtime based on ELD queried.
92217a42c45SSubhransu S. Prusty 		 */
92317a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.formats = formats;
92417a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.rates = rates;
92517a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.rate_max = rate_max;
92617a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.rate_min = rate_min;
92717a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.channels_min = 2;
92817a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.channels_max = 2;
92917a42c45SSubhransu S. Prusty 		hdmi_dais[i].ops = &hdmi_dai_ops;
93017a42c45SSubhransu S. Prusty 
93117a42c45SSubhransu S. Prusty 		i++;
93217a42c45SSubhransu S. Prusty 	}
93317a42c45SSubhransu S. Prusty 
93417a42c45SSubhransu S. Prusty 	*dais = hdmi_dais;
93517a42c45SSubhransu S. Prusty 
93617a42c45SSubhransu S. Prusty 	return 0;
93717a42c45SSubhransu S. Prusty }
93817a42c45SSubhransu S. Prusty 
93918382eadSSubhransu S. Prusty /*
94018382eadSSubhransu S. Prusty  * Parse all nodes and store the cvt/pin nids in array
94118382eadSSubhransu S. Prusty  * Add one time initialization for pin and cvt widgets
94218382eadSSubhransu S. Prusty  */
94317a42c45SSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
94417a42c45SSubhransu S. Prusty 		struct snd_soc_dai_driver **dais, int *num_dais)
94518382eadSSubhransu S. Prusty {
94618382eadSSubhransu S. Prusty 	hda_nid_t nid;
9473c83ac23SSudip Mukherjee 	int i, num_nodes;
94818382eadSSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
94918382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
95015b91447SSubhransu S. Prusty 	int ret;
95118382eadSSubhransu S. Prusty 
952211caab7SSubhransu S. Prusty 	hdac_hdmi_skl_enable_all_pins(hdac);
953211caab7SSubhransu S. Prusty 	hdac_hdmi_skl_enable_dp12(hdac);
954211caab7SSubhransu S. Prusty 
9553c83ac23SSudip Mukherjee 	num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
956541140d4SSubhransu S. Prusty 	if (!nid || num_nodes <= 0) {
95718382eadSSubhransu S. Prusty 		dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
95818382eadSSubhransu S. Prusty 		return -EINVAL;
95918382eadSSubhransu S. Prusty 	}
96018382eadSSubhransu S. Prusty 
9613c83ac23SSudip Mukherjee 	hdac->num_nodes = num_nodes;
96218382eadSSubhransu S. Prusty 	hdac->start_nid = nid;
96318382eadSSubhransu S. Prusty 
96418382eadSSubhransu S. Prusty 	for (i = 0; i < hdac->num_nodes; i++, nid++) {
96518382eadSSubhransu S. Prusty 		unsigned int caps;
96618382eadSSubhransu S. Prusty 		unsigned int type;
96718382eadSSubhransu S. Prusty 
96818382eadSSubhransu S. Prusty 		caps = get_wcaps(hdac, nid);
96918382eadSSubhransu S. Prusty 		type = get_wcaps_type(caps);
97018382eadSSubhransu S. Prusty 
97118382eadSSubhransu S. Prusty 		if (!(caps & AC_WCAP_DIGITAL))
97218382eadSSubhransu S. Prusty 			continue;
97318382eadSSubhransu S. Prusty 
97418382eadSSubhransu S. Prusty 		switch (type) {
97518382eadSSubhransu S. Prusty 
97618382eadSSubhransu S. Prusty 		case AC_WID_AUD_OUT:
97715b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_cvt(edev, nid);
97815b91447SSubhransu S. Prusty 			if (ret < 0)
97915b91447SSubhransu S. Prusty 				return ret;
98018382eadSSubhransu S. Prusty 			break;
98118382eadSSubhransu S. Prusty 
98218382eadSSubhransu S. Prusty 		case AC_WID_PIN:
98315b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_pin(edev, nid);
98415b91447SSubhransu S. Prusty 			if (ret < 0)
98515b91447SSubhransu S. Prusty 				return ret;
98618382eadSSubhransu S. Prusty 			break;
98718382eadSSubhransu S. Prusty 		}
98818382eadSSubhransu S. Prusty 	}
98918382eadSSubhransu S. Prusty 
99018382eadSSubhransu S. Prusty 	hdac->end_nid = nid;
99118382eadSSubhransu S. Prusty 
99215b91447SSubhransu S. Prusty 	if (!hdmi->num_pin || !hdmi->num_cvt)
99318382eadSSubhransu S. Prusty 		return -EIO;
99418382eadSSubhransu S. Prusty 
99517a42c45SSubhransu S. Prusty 	ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt);
99617a42c45SSubhransu S. Prusty 	if (ret) {
99717a42c45SSubhransu S. Prusty 		dev_err(&hdac->dev, "Failed to create dais with err: %d\n",
99817a42c45SSubhransu S. Prusty 							ret);
99917a42c45SSubhransu S. Prusty 		return ret;
100017a42c45SSubhransu S. Prusty 	}
100117a42c45SSubhransu S. Prusty 
100217a42c45SSubhransu S. Prusty 	*num_dais = hdmi->num_cvt;
100317a42c45SSubhransu S. Prusty 
100415b91447SSubhransu S. Prusty 	return hdac_hdmi_init_dai_map(edev);
100518382eadSSubhransu S. Prusty }
100618382eadSSubhransu S. Prusty 
1007b8a54545SSubhransu S. Prusty static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
1008b8a54545SSubhransu S. Prusty {
1009b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev = aptr;
1010b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
1011b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
1012b8a54545SSubhransu S. Prusty 	struct snd_soc_codec *codec = edev->scodec;
1013b8a54545SSubhransu S. Prusty 
1014b8a54545SSubhransu S. Prusty 	/* Don't know how this mapping is derived */
1015b8a54545SSubhransu S. Prusty 	hda_nid_t pin_nid = port + 0x04;
1016b8a54545SSubhransu S. Prusty 
1017b8a54545SSubhransu S. Prusty 	dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid);
1018b8a54545SSubhransu S. Prusty 
1019b8a54545SSubhransu S. Prusty 	/*
1020b8a54545SSubhransu S. Prusty 	 * skip notification during system suspend (but not in runtime PM);
1021b8a54545SSubhransu S. Prusty 	 * the state will be updated at resume. Also since the ELD and
1022b8a54545SSubhransu S. Prusty 	 * connection states are updated in anyway at the end of the resume,
1023b8a54545SSubhransu S. Prusty 	 * we can skip it when received during PM process.
1024b8a54545SSubhransu S. Prusty 	 */
1025b8a54545SSubhransu S. Prusty 	if (snd_power_get_state(codec->component.card->snd_card) !=
1026b8a54545SSubhransu S. Prusty 			SNDRV_CTL_POWER_D0)
1027b8a54545SSubhransu S. Prusty 		return;
1028b8a54545SSubhransu S. Prusty 
1029b8a54545SSubhransu S. Prusty 	if (atomic_read(&edev->hdac.in_pm))
1030b8a54545SSubhransu S. Prusty 		return;
1031b8a54545SSubhransu S. Prusty 
1032b8a54545SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
1033b8a54545SSubhransu S. Prusty 		if (pin->nid == pin_nid)
1034b8a54545SSubhransu S. Prusty 			hdac_hdmi_present_sense(pin, 1);
1035b8a54545SSubhransu S. Prusty 	}
1036b8a54545SSubhransu S. Prusty }
1037b8a54545SSubhransu S. Prusty 
1038b8a54545SSubhransu S. Prusty static struct i915_audio_component_audio_ops aops = {
1039b8a54545SSubhransu S. Prusty 	.pin_eld_notify	= hdac_hdmi_eld_notify_cb,
1040b8a54545SSubhransu S. Prusty };
1041b8a54545SSubhransu S. Prusty 
104218382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec)
104318382eadSSubhransu S. Prusty {
104418382eadSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
104518382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
104618382eadSSubhransu S. Prusty 	struct snd_soc_dapm_context *dapm =
104718382eadSSubhransu S. Prusty 		snd_soc_component_get_dapm(&codec->component);
1048b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
1049b8a54545SSubhransu S. Prusty 	int ret;
105018382eadSSubhransu S. Prusty 
105118382eadSSubhransu S. Prusty 	edev->scodec = codec;
105218382eadSSubhransu S. Prusty 
1053*79f4e922SSubhransu S. Prusty 	ret = create_fill_widget_route_map(dapm);
1054*79f4e922SSubhransu S. Prusty 	if (ret < 0)
1055*79f4e922SSubhransu S. Prusty 		return ret;
105618382eadSSubhransu S. Prusty 
1057b8a54545SSubhransu S. Prusty 	aops.audio_ptr = edev;
1058b8a54545SSubhransu S. Prusty 	ret = snd_hdac_i915_register_notifier(&aops);
1059b8a54545SSubhransu S. Prusty 	if (ret < 0) {
1060b8a54545SSubhransu S. Prusty 		dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n",
1061b8a54545SSubhransu S. Prusty 				ret);
1062b8a54545SSubhransu S. Prusty 		return ret;
1063b8a54545SSubhransu S. Prusty 	}
1064b8a54545SSubhransu S. Prusty 
1065b8a54545SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head)
1066b8a54545SSubhransu S. Prusty 		hdac_hdmi_present_sense(pin, 1);
1067b8a54545SSubhransu S. Prusty 
106818382eadSSubhransu S. Prusty 	/* Imp: Store the card pointer in hda_codec */
106918382eadSSubhransu S. Prusty 	edev->card = dapm->card->snd_card;
107018382eadSSubhransu S. Prusty 
1071e342ac08SSubhransu S. Prusty 	/*
1072e342ac08SSubhransu S. Prusty 	 * hdac_device core already sets the state to active and calls
1073e342ac08SSubhransu S. Prusty 	 * get_noresume. So enable runtime and set the device to suspend.
1074e342ac08SSubhransu S. Prusty 	 */
1075e342ac08SSubhransu S. Prusty 	pm_runtime_enable(&edev->hdac.dev);
1076e342ac08SSubhransu S. Prusty 	pm_runtime_put(&edev->hdac.dev);
1077e342ac08SSubhransu S. Prusty 	pm_runtime_suspend(&edev->hdac.dev);
1078e342ac08SSubhransu S. Prusty 
1079e342ac08SSubhransu S. Prusty 	return 0;
1080e342ac08SSubhransu S. Prusty }
1081e342ac08SSubhransu S. Prusty 
1082e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec)
1083e342ac08SSubhransu S. Prusty {
1084e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
1085e342ac08SSubhransu S. Prusty 
1086e342ac08SSubhransu S. Prusty 	pm_runtime_disable(&edev->hdac.dev);
108718382eadSSubhransu S. Prusty 	return 0;
108818382eadSSubhransu S. Prusty }
108918382eadSSubhransu S. Prusty 
109018382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = {
109118382eadSSubhransu S. Prusty 	.probe		= hdmi_codec_probe,
1092e342ac08SSubhransu S. Prusty 	.remove		= hdmi_codec_remove,
109318382eadSSubhransu S. Prusty 	.idle_bias_off	= true,
109418382eadSSubhransu S. Prusty };
109518382eadSSubhransu S. Prusty 
109618382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
109718382eadSSubhransu S. Prusty {
109818382eadSSubhransu S. Prusty 	struct hdac_device *codec = &edev->hdac;
109918382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi_priv;
110017a42c45SSubhransu S. Prusty 	struct snd_soc_dai_driver *hdmi_dais = NULL;
110117a42c45SSubhransu S. Prusty 	int num_dais = 0;
110218382eadSSubhransu S. Prusty 	int ret = 0;
110318382eadSSubhransu S. Prusty 
110418382eadSSubhransu S. Prusty 	hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
110518382eadSSubhransu S. Prusty 	if (hdmi_priv == NULL)
110618382eadSSubhransu S. Prusty 		return -ENOMEM;
110718382eadSSubhransu S. Prusty 
110818382eadSSubhransu S. Prusty 	edev->private_data = hdmi_priv;
110918382eadSSubhransu S. Prusty 
111018382eadSSubhransu S. Prusty 	dev_set_drvdata(&codec->dev, edev);
111118382eadSSubhransu S. Prusty 
111215b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->pin_list);
111315b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->cvt_list);
111415b91447SSubhransu S. Prusty 
111517a42c45SSubhransu S. Prusty 	ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais);
111617a42c45SSubhransu S. Prusty 	if (ret < 0) {
111717a42c45SSubhransu S. Prusty 		dev_err(&codec->dev,
111817a42c45SSubhransu S. Prusty 			"Failed in parse and map nid with err: %d\n", ret);
111918382eadSSubhransu S. Prusty 		return ret;
112017a42c45SSubhransu S. Prusty 	}
112118382eadSSubhransu S. Prusty 
112218382eadSSubhransu S. Prusty 	/* ASoC specific initialization */
112318382eadSSubhransu S. Prusty 	return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
112417a42c45SSubhransu S. Prusty 			hdmi_dais, num_dais);
112518382eadSSubhransu S. Prusty }
112618382eadSSubhransu S. Prusty 
112718382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
112818382eadSSubhransu S. Prusty {
112915b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
113015b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin, *pin_next;
113115b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt, *cvt_next;
113215b91447SSubhransu S. Prusty 
113318382eadSSubhransu S. Prusty 	snd_soc_unregister_codec(&edev->hdac.dev);
113418382eadSSubhransu S. Prusty 
113515b91447SSubhransu S. Prusty 	list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
113615b91447SSubhransu S. Prusty 		list_del(&cvt->head);
113715b91447SSubhransu S. Prusty 		kfree(cvt);
113815b91447SSubhransu S. Prusty 	}
113915b91447SSubhransu S. Prusty 
114015b91447SSubhransu S. Prusty 	list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
114115b91447SSubhransu S. Prusty 		list_del(&pin->head);
114215b91447SSubhransu S. Prusty 		kfree(pin);
114315b91447SSubhransu S. Prusty 	}
114415b91447SSubhransu S. Prusty 
114518382eadSSubhransu S. Prusty 	return 0;
114618382eadSSubhransu S. Prusty }
114718382eadSSubhransu S. Prusty 
1148e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM
1149e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev)
1150e342ac08SSubhransu S. Prusty {
1151e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
1152e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
115307f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
115407f083abSSubhransu S. Prusty 	int err;
1155e342ac08SSubhransu S. Prusty 
1156e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
1157e342ac08SSubhransu S. Prusty 
115807f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
115907f083abSSubhransu S. Prusty 	if (!bus)
116007f083abSSubhransu S. Prusty 		return 0;
116107f083abSSubhransu S. Prusty 
1162e342ac08SSubhransu S. Prusty 	/* Power down afg */
1163e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
1164e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
1165e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
1166e342ac08SSubhransu S. Prusty 
116707f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, false);
116807f083abSSubhransu S. Prusty 	if (err < 0) {
116907f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
117007f083abSSubhransu S. Prusty 		return err;
117107f083abSSubhransu S. Prusty 	}
117207f083abSSubhransu S. Prusty 
1173e342ac08SSubhransu S. Prusty 	return 0;
1174e342ac08SSubhransu S. Prusty }
1175e342ac08SSubhransu S. Prusty 
1176e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev)
1177e342ac08SSubhransu S. Prusty {
1178e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
1179e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
118007f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
118107f083abSSubhransu S. Prusty 	int err;
1182e342ac08SSubhransu S. Prusty 
1183e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
1184e342ac08SSubhransu S. Prusty 
118507f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
118607f083abSSubhransu S. Prusty 	if (!bus)
118707f083abSSubhransu S. Prusty 		return 0;
118807f083abSSubhransu S. Prusty 
118907f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, true);
119007f083abSSubhransu S. Prusty 	if (err < 0) {
119107f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
119207f083abSSubhransu S. Prusty 		return err;
119307f083abSSubhransu S. Prusty 	}
119407f083abSSubhransu S. Prusty 
1195e342ac08SSubhransu S. Prusty 	/* Power up afg */
1196e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
1197e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
1198e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
1199e342ac08SSubhransu S. Prusty 
1200e342ac08SSubhransu S. Prusty 	return 0;
1201e342ac08SSubhransu S. Prusty }
1202e342ac08SSubhransu S. Prusty #else
1203e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL
1204e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL
1205e342ac08SSubhransu S. Prusty #endif
1206e342ac08SSubhransu S. Prusty 
1207e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = {
1208e342ac08SSubhransu S. Prusty 	SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
1209e342ac08SSubhransu S. Prusty };
1210e342ac08SSubhransu S. Prusty 
121118382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = {
121218382eadSSubhransu S. Prusty 	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
121318382eadSSubhransu S. Prusty 	{}
121418382eadSSubhransu S. Prusty };
121518382eadSSubhransu S. Prusty 
121618382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
121718382eadSSubhransu S. Prusty 
121818382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = {
121918382eadSSubhransu S. Prusty 	. hdac = {
122018382eadSSubhransu S. Prusty 		.driver = {
122118382eadSSubhransu S. Prusty 			.name   = "HDMI HDA Codec",
1222e342ac08SSubhransu S. Prusty 			.pm = &hdac_hdmi_pm,
122318382eadSSubhransu S. Prusty 		},
122418382eadSSubhransu S. Prusty 		.id_table       = hdmi_list,
122518382eadSSubhransu S. Prusty 	},
122618382eadSSubhransu S. Prusty 	.probe          = hdac_hdmi_dev_probe,
122718382eadSSubhransu S. Prusty 	.remove         = hdac_hdmi_dev_remove,
122818382eadSSubhransu S. Prusty };
122918382eadSSubhransu S. Prusty 
123018382eadSSubhransu S. Prusty static int __init hdmi_init(void)
123118382eadSSubhransu S. Prusty {
123218382eadSSubhransu S. Prusty 	return snd_hda_ext_driver_register(&hdmi_driver);
123318382eadSSubhransu S. Prusty }
123418382eadSSubhransu S. Prusty 
123518382eadSSubhransu S. Prusty static void __exit hdmi_exit(void)
123618382eadSSubhransu S. Prusty {
123718382eadSSubhransu S. Prusty 	snd_hda_ext_driver_unregister(&hdmi_driver);
123818382eadSSubhransu S. Prusty }
123918382eadSSubhransu S. Prusty 
124018382eadSSubhransu S. Prusty module_init(hdmi_init);
124118382eadSSubhransu S. Prusty module_exit(hdmi_exit);
124218382eadSSubhransu S. Prusty 
124318382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2");
124418382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec");
124518382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
124618382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
1247