xref: /openbmc/linux/sound/soc/codecs/hdac_hdmi.c (revision 2428bca305e082885e08e7f3399db616daf3a51a)
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>
25*2428bca3SSubhransu 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>
30*2428bca3SSubhransu S. Prusty #include <sound/pcm_drm_eld.h>
3118382eadSSubhransu S. Prusty #include "../../hda/local.h"
3218382eadSSubhransu S. Prusty 
33b0362adbSSubhransu S. Prusty #define AMP_OUT_MUTE		0xb080
34b0362adbSSubhransu S. Prusty #define AMP_OUT_UNMUTE		0xb000
3518382eadSSubhransu S. Prusty #define PIN_OUT			(AC_PINCTL_OUT_EN)
36b0362adbSSubhransu S. Prusty 
3718382eadSSubhransu S. Prusty #define HDA_MAX_CONNECTIONS     32
3818382eadSSubhransu S. Prusty 
39b8a54545SSubhransu S. Prusty #define ELD_MAX_SIZE    256
40b8a54545SSubhransu S. Prusty #define ELD_FIXED_BYTES	20
41b8a54545SSubhransu S. Prusty 
4218382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params {
4318382eadSSubhransu S. Prusty 	unsigned int channels_min;
4418382eadSSubhransu S. Prusty 	unsigned int channels_max;
4518382eadSSubhransu S. Prusty 	u32 rates;
4618382eadSSubhransu S. Prusty 	u64 formats;
4718382eadSSubhransu S. Prusty 	unsigned int maxbps;
4818382eadSSubhransu S. Prusty };
4918382eadSSubhransu S. Prusty 
5018382eadSSubhransu S. Prusty struct hdac_hdmi_cvt {
5115b91447SSubhransu S. Prusty 	struct list_head head;
5218382eadSSubhransu S. Prusty 	hda_nid_t nid;
5318382eadSSubhransu S. Prusty 	struct hdac_hdmi_cvt_params params;
5418382eadSSubhransu S. Prusty };
5518382eadSSubhransu S. Prusty 
56b8a54545SSubhransu S. Prusty struct hdac_hdmi_eld {
57b8a54545SSubhransu S. Prusty 	bool	monitor_present;
58b8a54545SSubhransu S. Prusty 	bool	eld_valid;
59b8a54545SSubhransu S. Prusty 	int	eld_size;
60b8a54545SSubhransu S. Prusty 	char    eld_buffer[ELD_MAX_SIZE];
61b8a54545SSubhransu S. Prusty };
62b8a54545SSubhransu S. Prusty 
6318382eadSSubhransu S. Prusty struct hdac_hdmi_pin {
6415b91447SSubhransu S. Prusty 	struct list_head head;
6518382eadSSubhransu S. Prusty 	hda_nid_t nid;
6618382eadSSubhransu S. Prusty 	int num_mux_nids;
6718382eadSSubhransu S. Prusty 	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
68b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_eld eld;
69b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev;
70b8a54545SSubhransu S. Prusty 	int repoll_count;
71b8a54545SSubhransu S. Prusty 	struct delayed_work work;
7218382eadSSubhransu S. Prusty };
7318382eadSSubhransu S. Prusty 
7418382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map {
7518382eadSSubhransu S. Prusty 	int dai_id;
7615b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
7715b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
7818382eadSSubhransu S. Prusty };
7918382eadSSubhransu S. Prusty 
8018382eadSSubhransu S. Prusty struct hdac_hdmi_priv {
8118382eadSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map dai_map[3];
8215b91447SSubhransu S. Prusty 	struct list_head pin_list;
8315b91447SSubhransu S. Prusty 	struct list_head cvt_list;
8415b91447SSubhransu S. Prusty 	int num_pin;
8515b91447SSubhransu S. Prusty 	int num_cvt;
8618382eadSSubhransu S. Prusty };
8718382eadSSubhransu S. Prusty 
88e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
89e342ac08SSubhransu S. Prusty {
9051b2c425SGeliang Tang 	struct hdac_device *hdac = dev_to_hdac_dev(dev);
91e342ac08SSubhransu S. Prusty 
9251b2c425SGeliang Tang 	return to_ehdac_device(hdac);
93e342ac08SSubhransu S. Prusty }
94e342ac08SSubhransu S. Prusty 
95*2428bca3SSubhransu S. Prusty static unsigned int sad_format(const u8 *sad)
96*2428bca3SSubhransu S. Prusty {
97*2428bca3SSubhransu S. Prusty 	return ((sad[0] >> 0x3) & 0x1f);
98*2428bca3SSubhransu S. Prusty }
99*2428bca3SSubhransu S. Prusty 
100*2428bca3SSubhransu S. Prusty static unsigned int sad_sample_bits_lpcm(const u8 *sad)
101*2428bca3SSubhransu S. Prusty {
102*2428bca3SSubhransu S. Prusty 	return (sad[2] & 7);
103*2428bca3SSubhransu S. Prusty }
104*2428bca3SSubhransu S. Prusty 
105*2428bca3SSubhransu S. Prusty static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime,
106*2428bca3SSubhransu S. Prusty 						void *eld)
107*2428bca3SSubhransu S. Prusty {
108*2428bca3SSubhransu S. Prusty 	u64 formats = SNDRV_PCM_FMTBIT_S16;
109*2428bca3SSubhransu S. Prusty 	int i;
110*2428bca3SSubhransu S. Prusty 	const u8 *sad, *eld_buf = eld;
111*2428bca3SSubhransu S. Prusty 
112*2428bca3SSubhransu S. Prusty 	sad = drm_eld_sad(eld_buf);
113*2428bca3SSubhransu S. Prusty 	if (!sad)
114*2428bca3SSubhransu S. Prusty 		goto format_constraint;
115*2428bca3SSubhransu S. Prusty 
116*2428bca3SSubhransu S. Prusty 	for (i = drm_eld_sad_count(eld_buf); i > 0; i--, sad += 3) {
117*2428bca3SSubhransu S. Prusty 		if (sad_format(sad) == 1) { /* AUDIO_CODING_TYPE_LPCM */
118*2428bca3SSubhransu S. Prusty 
119*2428bca3SSubhransu S. Prusty 			/*
120*2428bca3SSubhransu S. Prusty 			 * the controller support 20 and 24 bits in 32 bit
121*2428bca3SSubhransu S. Prusty 			 * container so we set S32
122*2428bca3SSubhransu S. Prusty 			 */
123*2428bca3SSubhransu S. Prusty 			if (sad_sample_bits_lpcm(sad) & 0x6)
124*2428bca3SSubhransu S. Prusty 				formats |= SNDRV_PCM_FMTBIT_S32;
125*2428bca3SSubhransu S. Prusty 		}
126*2428bca3SSubhransu S. Prusty 	}
127*2428bca3SSubhransu S. Prusty 
128*2428bca3SSubhransu S. Prusty format_constraint:
129*2428bca3SSubhransu S. Prusty 	return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT,
130*2428bca3SSubhransu S. Prusty 				formats);
131*2428bca3SSubhransu S. Prusty 
132*2428bca3SSubhransu S. Prusty }
133*2428bca3SSubhransu S. Prusty 
134b8a54545SSubhransu S. Prusty  /* HDMI ELD routines */
135b8a54545SSubhransu S. Prusty static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec,
136b8a54545SSubhransu S. Prusty 				hda_nid_t nid, int byte_index)
137b8a54545SSubhransu S. Prusty {
138b8a54545SSubhransu S. Prusty 	unsigned int val;
139b8a54545SSubhransu S. Prusty 
140b8a54545SSubhransu S. Prusty 	val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD,
141b8a54545SSubhransu S. Prusty 							byte_index);
142b8a54545SSubhransu S. Prusty 
143b8a54545SSubhransu S. Prusty 	dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n",
144b8a54545SSubhransu S. Prusty 					byte_index, val);
145b8a54545SSubhransu S. Prusty 
146b8a54545SSubhransu S. Prusty 	return val;
147b8a54545SSubhransu S. Prusty }
148b8a54545SSubhransu S. Prusty 
149b8a54545SSubhransu S. Prusty static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid)
150b8a54545SSubhransu S. Prusty {
151b8a54545SSubhransu S. Prusty 	return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
152b8a54545SSubhransu S. Prusty 						 AC_DIPSIZE_ELD_BUF);
153b8a54545SSubhransu S. Prusty }
154b8a54545SSubhransu S. Prusty 
155b8a54545SSubhransu S. Prusty /*
156b8a54545SSubhransu S. Prusty  * This function queries the ELD size and ELD data and fills in the buffer
157b8a54545SSubhransu S. Prusty  * passed by user
158b8a54545SSubhransu S. Prusty  */
159b8a54545SSubhransu S. Prusty static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid,
160b8a54545SSubhransu S. Prusty 			     unsigned char *buf, int *eld_size)
161b8a54545SSubhransu S. Prusty {
162b8a54545SSubhransu S. Prusty 	int i, size, ret = 0;
163b8a54545SSubhransu S. Prusty 
164b8a54545SSubhransu S. Prusty 	/*
165b8a54545SSubhransu S. Prusty 	 * ELD size is initialized to zero in caller function. If no errors and
166b8a54545SSubhransu S. Prusty 	 * ELD is valid, actual eld_size is assigned.
167b8a54545SSubhransu S. Prusty 	 */
168b8a54545SSubhransu S. Prusty 
169b8a54545SSubhransu S. Prusty 	size = hdac_hdmi_get_eld_size(codec, nid);
170b8a54545SSubhransu S. Prusty 	if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
171b8a54545SSubhransu S. Prusty 		dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size);
172b8a54545SSubhransu S. Prusty 		return -ERANGE;
173b8a54545SSubhransu S. Prusty 	}
174b8a54545SSubhransu S. Prusty 
175b8a54545SSubhransu S. Prusty 	/* set ELD buffer */
176b8a54545SSubhransu S. Prusty 	for (i = 0; i < size; i++) {
177b8a54545SSubhransu S. Prusty 		unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i);
178b8a54545SSubhransu S. Prusty 		/*
179b8a54545SSubhransu S. Prusty 		 * Graphics driver might be writing to ELD buffer right now.
180b8a54545SSubhransu S. Prusty 		 * Just abort. The caller will repoll after a while.
181b8a54545SSubhransu S. Prusty 		 */
182b8a54545SSubhransu S. Prusty 		if (!(val & AC_ELDD_ELD_VALID)) {
183b8a54545SSubhransu S. Prusty 			dev_err(&codec->dev,
184b8a54545SSubhransu S. Prusty 				"HDMI: invalid ELD data byte %d\n", i);
185b8a54545SSubhransu S. Prusty 			ret = -EINVAL;
186b8a54545SSubhransu S. Prusty 			goto error;
187b8a54545SSubhransu S. Prusty 		}
188b8a54545SSubhransu S. Prusty 		val &= AC_ELDD_ELD_DATA;
189b8a54545SSubhransu S. Prusty 		/*
190b8a54545SSubhransu S. Prusty 		 * The first byte cannot be zero. This can happen on some DVI
191b8a54545SSubhransu S. Prusty 		 * connections. Some Intel chips may also need some 250ms delay
192b8a54545SSubhransu S. Prusty 		 * to return non-zero ELD data, even when the graphics driver
193b8a54545SSubhransu S. Prusty 		 * correctly writes ELD content before setting ELD_valid bit.
194b8a54545SSubhransu S. Prusty 		 */
195b8a54545SSubhransu S. Prusty 		if (!val && !i) {
196b8a54545SSubhransu S. Prusty 			dev_err(&codec->dev, "HDMI: 0 ELD data\n");
197b8a54545SSubhransu S. Prusty 			ret = -EINVAL;
198b8a54545SSubhransu S. Prusty 			goto error;
199b8a54545SSubhransu S. Prusty 		}
200b8a54545SSubhransu S. Prusty 		buf[i] = val;
201b8a54545SSubhransu S. Prusty 	}
202b8a54545SSubhransu S. Prusty 
203b8a54545SSubhransu S. Prusty 	*eld_size = size;
204b8a54545SSubhransu S. Prusty error:
205b8a54545SSubhransu S. Prusty 	return ret;
206b8a54545SSubhransu S. Prusty }
207b8a54545SSubhransu S. Prusty 
208b0362adbSSubhransu S. Prusty static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
209b0362adbSSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid,
210b0362adbSSubhransu S. Prusty 				u32 stream_tag, int format)
211b0362adbSSubhransu S. Prusty {
212b0362adbSSubhransu S. Prusty 	unsigned int val;
213b0362adbSSubhransu S. Prusty 
214b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
215b0362adbSSubhransu S. Prusty 			cvt_nid, pin_nid, stream_tag, format);
216b0362adbSSubhransu S. Prusty 
217b0362adbSSubhransu S. Prusty 	val = (stream_tag << 4);
218b0362adbSSubhransu S. Prusty 
219b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
220b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, val);
221b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
222b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, format);
223b0362adbSSubhransu S. Prusty 
224b0362adbSSubhransu S. Prusty 	return 0;
225b0362adbSSubhransu S. Prusty }
226b0362adbSSubhransu S. Prusty 
227a657f1d0SSubhransu S. Prusty static void
228a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
229a657f1d0SSubhransu S. Prusty 				int packet_index, int byte_index)
230a657f1d0SSubhransu S. Prusty {
231a657f1d0SSubhransu S. Prusty 	int val;
232a657f1d0SSubhransu S. Prusty 
233a657f1d0SSubhransu S. Prusty 	val = (packet_index << 5) | (byte_index & 0x1f);
234a657f1d0SSubhransu S. Prusty 
235a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
236a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_INDEX, val);
237a657f1d0SSubhransu S. Prusty }
238a657f1d0SSubhransu S. Prusty 
239a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
240a657f1d0SSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid)
241a657f1d0SSubhransu S. Prusty {
242a657f1d0SSubhransu S. Prusty 	uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
243a657f1d0SSubhransu S. Prusty 	struct hdmi_audio_infoframe frame;
244a657f1d0SSubhransu S. Prusty 	u8 *dip = (u8 *)&frame;
245a657f1d0SSubhransu S. Prusty 	int ret;
246a657f1d0SSubhransu S. Prusty 	int i;
247a657f1d0SSubhransu S. Prusty 
248a657f1d0SSubhransu S. Prusty 	hdmi_audio_infoframe_init(&frame);
249a657f1d0SSubhransu S. Prusty 
250a657f1d0SSubhransu S. Prusty 	/* Default stereo for now */
251a657f1d0SSubhransu S. Prusty 	frame.channels = 2;
252a657f1d0SSubhransu S. Prusty 
253a657f1d0SSubhransu S. Prusty 	/* setup channel count */
254a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
255a657f1d0SSubhransu S. Prusty 			    AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1);
256a657f1d0SSubhransu S. Prusty 
257a657f1d0SSubhransu S. Prusty 	ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
258a657f1d0SSubhransu S. Prusty 	if (ret < 0)
259a657f1d0SSubhransu S. Prusty 		return ret;
260a657f1d0SSubhransu S. Prusty 
261a657f1d0SSubhransu S. Prusty 	/* stop infoframe transmission */
262a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
263a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
264a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
265a657f1d0SSubhransu S. Prusty 
266a657f1d0SSubhransu S. Prusty 
267a657f1d0SSubhransu S. Prusty 	/*  Fill infoframe. Index auto-incremented */
268a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
269a657f1d0SSubhransu S. Prusty 	for (i = 0; i < sizeof(frame); i++)
270a657f1d0SSubhransu S. Prusty 		snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
271a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
272a657f1d0SSubhransu S. Prusty 
273a657f1d0SSubhransu S. Prusty 	/* Start infoframe */
274a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
275a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
276a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
277a657f1d0SSubhransu S. Prusty 
278a657f1d0SSubhransu S. Prusty 	return 0;
279a657f1d0SSubhransu S. Prusty }
280a657f1d0SSubhransu S. Prusty 
281b0362adbSSubhransu S. Prusty static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
282b0362adbSSubhransu S. Prusty 		struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
283b0362adbSSubhransu S. Prusty {
284b0362adbSSubhransu S. Prusty 	/* Power up pin widget */
28515b91447SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
28615b91447SSubhransu S. Prusty 						pwr_state))
28715b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
288b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
289b0362adbSSubhransu S. Prusty 
290b0362adbSSubhransu S. Prusty 	/* Power up converter */
29115b91447SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
29215b91447SSubhransu S. Prusty 						pwr_state))
29315b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
294b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
295b0362adbSSubhransu S. Prusty }
296b0362adbSSubhransu S. Prusty 
297b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
298b0362adbSSubhransu S. Prusty 				struct snd_soc_dai *dai)
299b0362adbSSubhransu S. Prusty {
300b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
301b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
302b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
303b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
304a657f1d0SSubhransu S. Prusty 	int ret;
305b0362adbSSubhransu S. Prusty 
306b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
307b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
308b0362adbSSubhransu S. Prusty 		return -ENODEV;
309b0362adbSSubhransu S. Prusty 	}
310b0362adbSSubhransu S. Prusty 
311b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
312b0362adbSSubhransu S. Prusty 
313b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
314b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
315b0362adbSSubhransu S. Prusty 			dd->stream_tag,	dd->format);
316b0362adbSSubhransu S. Prusty 
31715b91447SSubhransu S. Prusty 	ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
31815b91447SSubhransu S. Prusty 						dai_map->pin->nid);
319a657f1d0SSubhransu S. Prusty 	if (ret < 0)
320a657f1d0SSubhransu S. Prusty 		return ret;
321a657f1d0SSubhransu S. Prusty 
32215b91447SSubhransu S. Prusty 	return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
32315b91447SSubhransu S. Prusty 			dai_map->pin->nid, dd->stream_tag, dd->format);
324b0362adbSSubhransu S. Prusty }
325b0362adbSSubhransu S. Prusty 
326b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
327b0362adbSSubhransu S. Prusty 	struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
328b0362adbSSubhransu S. Prusty {
329b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
330b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
331b0362adbSSubhransu S. Prusty 
332b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
333b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
334b0362adbSSubhransu S. Prusty 		return -ENODEV;
335b0362adbSSubhransu S. Prusty 	}
336b0362adbSSubhransu S. Prusty 
337b0362adbSSubhransu S. Prusty 	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
3388d33ab24SSudip Mukherjee 	if (!dd)
3398d33ab24SSudip Mukherjee 		return -ENOMEM;
340b0362adbSSubhransu S. Prusty 	dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
341b0362adbSSubhransu S. Prusty 			params_channels(hparams), params_format(hparams),
342b0362adbSSubhransu S. Prusty 			24, 0);
343b0362adbSSubhransu S. Prusty 
344b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
345b0362adbSSubhransu S. Prusty 
346b0362adbSSubhransu S. Prusty 	return 0;
347b0362adbSSubhransu S. Prusty }
348b0362adbSSubhransu S. Prusty 
349b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
350b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
351b0362adbSSubhransu S. Prusty {
352b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
353b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
354b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
355b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
356b0362adbSSubhransu S. Prusty 
357b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
358b0362adbSSubhransu S. Prusty 
35915b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
360b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, 0);
36115b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
362b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, 0);
363b0362adbSSubhransu S. Prusty 
364b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
365b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, NULL);
366b0362adbSSubhransu S. Prusty 
367b0362adbSSubhransu S. Prusty 	kfree(dd);
368b0362adbSSubhransu S. Prusty 
369b0362adbSSubhransu S. Prusty 	return 0;
370b0362adbSSubhransu S. Prusty }
371b0362adbSSubhransu S. Prusty 
372b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
373b0362adbSSubhransu S. Prusty 			struct snd_soc_dai *dai)
374b0362adbSSubhransu S. Prusty {
375b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
376b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
377b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
378*2428bca3SSubhransu S. Prusty 	int ret;
379b0362adbSSubhransu S. Prusty 
380b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
381b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
382b0362adbSSubhransu S. Prusty 		return -ENODEV;
383b0362adbSSubhransu S. Prusty 	}
384b0362adbSSubhransu S. Prusty 
385b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
386b0362adbSSubhransu S. Prusty 
387b8a54545SSubhransu S. Prusty 	if ((!dai_map->pin->eld.monitor_present) ||
388b8a54545SSubhransu S. Prusty 			(!dai_map->pin->eld.eld_valid)) {
389b0362adbSSubhransu S. Prusty 
390b8a54545SSubhransu S. Prusty 		dev_err(&hdac->hdac.dev,
391b8a54545SSubhransu S. Prusty 				"Failed: montior present? %d ELD valid?: %d\n",
392b8a54545SSubhransu S. Prusty 				dai_map->pin->eld.monitor_present,
393b8a54545SSubhransu S. Prusty 				dai_map->pin->eld.eld_valid);
394b8a54545SSubhransu S. Prusty 
395b0362adbSSubhransu S. Prusty 		return -ENODEV;
396b0362adbSSubhransu S. Prusty 	}
397b0362adbSSubhransu S. Prusty 
398b0362adbSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
399b0362adbSSubhransu S. Prusty 
40015b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
401b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
402b0362adbSSubhransu S. Prusty 
403*2428bca3SSubhransu S. Prusty 	ret = hdac_hdmi_eld_limit_formats(substream->runtime,
404*2428bca3SSubhransu S. Prusty 				dai_map->pin->eld.eld_buffer);
405*2428bca3SSubhransu S. Prusty 	if (ret < 0)
406*2428bca3SSubhransu S. Prusty 		return ret;
407b0362adbSSubhransu S. Prusty 
408*2428bca3SSubhransu S. Prusty 	return snd_pcm_hw_constraint_eld(substream->runtime,
409*2428bca3SSubhransu S. Prusty 				dai_map->pin->eld.eld_buffer);
410b0362adbSSubhransu S. Prusty }
411b0362adbSSubhransu S. Prusty 
412b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
413b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
414b0362adbSSubhransu S. Prusty {
415b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
416b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
417b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
418b0362adbSSubhransu S. Prusty 
419b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
420b0362adbSSubhransu S. Prusty 
421b0362adbSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
422b0362adbSSubhransu S. Prusty 
42315b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
424b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
425b0362adbSSubhransu S. Prusty }
426b0362adbSSubhransu S. Prusty 
42718382eadSSubhransu S. Prusty static int
42818382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
42918382eadSSubhransu S. Prusty {
43018382eadSSubhransu S. Prusty 	int err;
43118382eadSSubhransu S. Prusty 
43218382eadSSubhransu S. Prusty 	/* Only stereo supported as of now */
43318382eadSSubhransu S. Prusty 	cvt->params.channels_min = cvt->params.channels_max = 2;
43418382eadSSubhransu S. Prusty 
43518382eadSSubhransu S. Prusty 	err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
43618382eadSSubhransu S. Prusty 			&cvt->params.rates,
43718382eadSSubhransu S. Prusty 			&cvt->params.formats,
43818382eadSSubhransu S. Prusty 			&cvt->params.maxbps);
43918382eadSSubhransu S. Prusty 	if (err < 0)
44018382eadSSubhransu S. Prusty 		dev_err(&hdac->dev,
44118382eadSSubhransu S. Prusty 			"Failed to query pcm params for nid %d: %d\n",
44218382eadSSubhransu S. Prusty 			cvt->nid, err);
44318382eadSSubhransu S. Prusty 
44418382eadSSubhransu S. Prusty 	return err;
44518382eadSSubhransu S. Prusty }
44618382eadSSubhransu S. Prusty 
44718382eadSSubhransu S. Prusty static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
44818382eadSSubhransu S. Prusty 				enum snd_soc_dapm_type id,
44918382eadSSubhransu S. Prusty 				const char *wname, const char *stream)
45018382eadSSubhransu S. Prusty {
45118382eadSSubhransu S. Prusty 	w->id = id;
45218382eadSSubhransu S. Prusty 	w->name = wname;
45318382eadSSubhransu S. Prusty 	w->sname = stream;
45418382eadSSubhransu S. Prusty 	w->reg = SND_SOC_NOPM;
45518382eadSSubhransu S. Prusty 	w->shift = 0;
45618382eadSSubhransu S. Prusty 	w->kcontrol_news = NULL;
45718382eadSSubhransu S. Prusty 	w->num_kcontrols = 0;
45818382eadSSubhransu S. Prusty 	w->priv = NULL;
45918382eadSSubhransu S. Prusty }
46018382eadSSubhransu S. Prusty 
46118382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
46218382eadSSubhransu S. Prusty 		const char *sink, const char *control, const char *src)
46318382eadSSubhransu S. Prusty {
46418382eadSSubhransu S. Prusty 	route->sink = sink;
46518382eadSSubhransu S. Prusty 	route->source = src;
46618382eadSSubhransu S. Prusty 	route->control = control;
46718382eadSSubhransu S. Prusty 	route->connected = NULL;
46818382eadSSubhransu S. Prusty }
46918382eadSSubhransu S. Prusty 
47018382eadSSubhransu S. Prusty static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
47118382eadSSubhransu S. Prusty 					struct hdac_hdmi_dai_pin_map *dai_map)
47218382eadSSubhransu S. Prusty {
47318382eadSSubhransu S. Prusty 	struct snd_soc_dapm_route route[1];
47418382eadSSubhransu S. Prusty 	struct snd_soc_dapm_widget widgets[2] = { {0} };
47518382eadSSubhransu S. Prusty 
47618382eadSSubhransu S. Prusty 	memset(&route, 0, sizeof(route));
47718382eadSSubhransu S. Prusty 
47818382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
47918382eadSSubhransu S. Prusty 			"hif1 Output", NULL);
48018382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
48118382eadSSubhransu S. Prusty 			"Coverter 1", "hif1");
48218382eadSSubhransu S. Prusty 
48318382eadSSubhransu S. Prusty 	hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
48418382eadSSubhransu S. Prusty 
48518382eadSSubhransu S. Prusty 	snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
48618382eadSSubhransu S. Prusty 	snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
48718382eadSSubhransu S. Prusty }
48818382eadSSubhransu S. Prusty 
48915b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
49018382eadSSubhransu S. Prusty {
49115b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
49215b91447SSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
49315b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
49415b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
49518382eadSSubhransu S. Prusty 
49615b91447SSubhransu S. Prusty 	if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
49715b91447SSubhransu S. Prusty 		return -EINVAL;
49818382eadSSubhransu S. Prusty 
49915b91447SSubhransu S. Prusty 	/*
50015b91447SSubhransu S. Prusty 	 * Currently on board only 1 pin and 1 converter is enabled for
50115b91447SSubhransu S. Prusty 	 * simplification, more will be added eventually
50215b91447SSubhransu S. Prusty 	 * So using fixed map for dai_id:pin:cvt
50315b91447SSubhransu S. Prusty 	 */
50415b91447SSubhransu S. Prusty 	cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
50515b91447SSubhransu S. Prusty 	pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
50618382eadSSubhransu S. Prusty 
50715b91447SSubhransu S. Prusty 	dai_map->dai_id = 0;
50815b91447SSubhransu S. Prusty 	dai_map->pin = pin;
50915b91447SSubhransu S. Prusty 
51015b91447SSubhransu S. Prusty 	dai_map->cvt = cvt;
51118382eadSSubhransu S. Prusty 
51218382eadSSubhransu S. Prusty 	/* Enable out path for this pin widget */
51315b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
51418382eadSSubhransu S. Prusty 			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
51518382eadSSubhransu S. Prusty 
51618382eadSSubhransu S. Prusty 	/* Enable transmission */
51715b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
51818382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_1, 1);
51918382eadSSubhransu S. Prusty 
52018382eadSSubhransu S. Prusty 	/* Category Code (CC) to zero */
52115b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
52218382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_2, 0);
52318382eadSSubhransu S. Prusty 
52415b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
52518382eadSSubhransu S. Prusty 			AC_VERB_SET_CONNECT_SEL, 0);
52618382eadSSubhransu S. Prusty 
52715b91447SSubhransu S. Prusty 	return 0;
52815b91447SSubhransu S. Prusty }
52915b91447SSubhransu S. Prusty 
53015b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
53115b91447SSubhransu S. Prusty {
53215b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
53315b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
53415b91447SSubhransu S. Prusty 
53515b91447SSubhransu S. Prusty 	cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
53615b91447SSubhransu S. Prusty 	if (!cvt)
53715b91447SSubhransu S. Prusty 		return -ENOMEM;
53815b91447SSubhransu S. Prusty 
53915b91447SSubhransu S. Prusty 	cvt->nid = nid;
54015b91447SSubhransu S. Prusty 
54115b91447SSubhransu S. Prusty 	list_add_tail(&cvt->head, &hdmi->cvt_list);
54215b91447SSubhransu S. Prusty 	hdmi->num_cvt++;
54315b91447SSubhransu S. Prusty 
54415b91447SSubhransu S. Prusty 	return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
54515b91447SSubhransu S. Prusty }
54615b91447SSubhransu S. Prusty 
547b8a54545SSubhransu S. Prusty static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
548b8a54545SSubhransu S. Prusty {
549b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev = pin->edev;
550b8a54545SSubhransu S. Prusty 	int val;
551b8a54545SSubhransu S. Prusty 
552b8a54545SSubhransu S. Prusty 	if (!edev)
553b8a54545SSubhransu S. Prusty 		return;
554b8a54545SSubhransu S. Prusty 
555b8a54545SSubhransu S. Prusty 	pin->repoll_count = repoll;
556b8a54545SSubhransu S. Prusty 
557b8a54545SSubhransu S. Prusty 	pm_runtime_get_sync(&edev->hdac.dev);
558b8a54545SSubhransu S. Prusty 	val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0,
559b8a54545SSubhransu S. Prusty 					AC_VERB_GET_PIN_SENSE, 0);
560b8a54545SSubhransu S. Prusty 
561b8a54545SSubhransu S. Prusty 	dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n",
562b8a54545SSubhransu S. Prusty 						val, pin->nid);
563b8a54545SSubhransu S. Prusty 
564b8a54545SSubhransu S. Prusty 	pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE);
565b8a54545SSubhransu S. Prusty 	pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV);
566b8a54545SSubhransu S. Prusty 
567b8a54545SSubhransu S. Prusty 	if (!pin->eld.monitor_present || !pin->eld.eld_valid) {
568b8a54545SSubhransu S. Prusty 
569b8a54545SSubhransu S. Prusty 		dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n",
570b8a54545SSubhransu S. Prusty 						__func__, pin->nid);
571b8a54545SSubhransu S. Prusty 		goto put_hdac_device;
572b8a54545SSubhransu S. Prusty 	}
573b8a54545SSubhransu S. Prusty 
574b8a54545SSubhransu S. Prusty 	if (pin->eld.monitor_present && pin->eld.eld_valid) {
575b8a54545SSubhransu S. Prusty 		/* TODO: use i915 component for reading ELD later */
576b8a54545SSubhransu S. Prusty 		if (hdac_hdmi_get_eld(&edev->hdac, pin->nid,
577b8a54545SSubhransu S. Prusty 				pin->eld.eld_buffer,
578b8a54545SSubhransu S. Prusty 				&pin->eld.eld_size) == 0) {
579b8a54545SSubhransu S. Prusty 
580b8a54545SSubhransu S. Prusty 			print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET,
581b8a54545SSubhransu S. Prusty 					pin->eld.eld_buffer, pin->eld.eld_size);
582b8a54545SSubhransu S. Prusty 		} else {
583b8a54545SSubhransu S. Prusty 			pin->eld.monitor_present = false;
584b8a54545SSubhransu S. Prusty 			pin->eld.eld_valid = false;
585b8a54545SSubhransu S. Prusty 		}
586b8a54545SSubhransu S. Prusty 	}
587b8a54545SSubhransu S. Prusty 
588b8a54545SSubhransu S. Prusty 	/*
589b8a54545SSubhransu S. Prusty 	 * Sometimes the pin_sense may present invalid monitor
590b8a54545SSubhransu S. Prusty 	 * present and eld_valid. If ELD data is not valid, loop few
591b8a54545SSubhransu S. Prusty 	 * more times to get correct pin sense and valid ELD.
592b8a54545SSubhransu S. Prusty 	 */
593b8a54545SSubhransu S. Prusty 	if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll)
594b8a54545SSubhransu S. Prusty 		schedule_delayed_work(&pin->work, msecs_to_jiffies(300));
595b8a54545SSubhransu S. Prusty 
596b8a54545SSubhransu S. Prusty put_hdac_device:
597b8a54545SSubhransu S. Prusty 	pm_runtime_put_sync(&edev->hdac.dev);
598b8a54545SSubhransu S. Prusty }
599b8a54545SSubhransu S. Prusty 
600b8a54545SSubhransu S. Prusty static void hdac_hdmi_repoll_eld(struct work_struct *work)
601b8a54545SSubhransu S. Prusty {
602b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin =
603b8a54545SSubhransu S. Prusty 		container_of(to_delayed_work(work), struct hdac_hdmi_pin, work);
604b8a54545SSubhransu S. Prusty 
605b8a54545SSubhransu S. Prusty 	/* picked from legacy HDA driver */
606b8a54545SSubhransu S. Prusty 	if (pin->repoll_count++ > 6)
607b8a54545SSubhransu S. Prusty 		pin->repoll_count = 0;
608b8a54545SSubhransu S. Prusty 
609b8a54545SSubhransu S. Prusty 	hdac_hdmi_present_sense(pin, pin->repoll_count);
610b8a54545SSubhransu S. Prusty }
611b8a54545SSubhransu S. Prusty 
61215b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
61315b91447SSubhransu S. Prusty {
61415b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
61515b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
61615b91447SSubhransu S. Prusty 
61715b91447SSubhransu S. Prusty 	pin = kzalloc(sizeof(*pin), GFP_KERNEL);
61815b91447SSubhransu S. Prusty 	if (!pin)
61915b91447SSubhransu S. Prusty 		return -ENOMEM;
62015b91447SSubhransu S. Prusty 
62115b91447SSubhransu S. Prusty 	pin->nid = nid;
62215b91447SSubhransu S. Prusty 
62315b91447SSubhransu S. Prusty 	list_add_tail(&pin->head, &hdmi->pin_list);
62415b91447SSubhransu S. Prusty 	hdmi->num_pin++;
62515b91447SSubhransu S. Prusty 
626b8a54545SSubhransu S. Prusty 	pin->edev = edev;
627b8a54545SSubhransu S. Prusty 	INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
628b8a54545SSubhransu S. Prusty 
62915b91447SSubhransu S. Prusty 	return 0;
63018382eadSSubhransu S. Prusty }
63118382eadSSubhransu S. Prusty 
63218382eadSSubhransu S. Prusty /*
63318382eadSSubhransu S. Prusty  * Parse all nodes and store the cvt/pin nids in array
63418382eadSSubhransu S. Prusty  * Add one time initialization for pin and cvt widgets
63518382eadSSubhransu S. Prusty  */
63618382eadSSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
63718382eadSSubhransu S. Prusty {
63818382eadSSubhransu S. Prusty 	hda_nid_t nid;
6393c83ac23SSudip Mukherjee 	int i, num_nodes;
64018382eadSSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
64118382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
64215b91447SSubhransu S. Prusty 	int ret;
64318382eadSSubhransu S. Prusty 
6443c83ac23SSudip Mukherjee 	num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
645541140d4SSubhransu S. Prusty 	if (!nid || num_nodes <= 0) {
64618382eadSSubhransu S. Prusty 		dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
64718382eadSSubhransu S. Prusty 		return -EINVAL;
64818382eadSSubhransu S. Prusty 	}
64918382eadSSubhransu S. Prusty 
6503c83ac23SSudip Mukherjee 	hdac->num_nodes = num_nodes;
65118382eadSSubhransu S. Prusty 	hdac->start_nid = nid;
65218382eadSSubhransu S. Prusty 
65318382eadSSubhransu S. Prusty 	for (i = 0; i < hdac->num_nodes; i++, nid++) {
65418382eadSSubhransu S. Prusty 		unsigned int caps;
65518382eadSSubhransu S. Prusty 		unsigned int type;
65618382eadSSubhransu S. Prusty 
65718382eadSSubhransu S. Prusty 		caps = get_wcaps(hdac, nid);
65818382eadSSubhransu S. Prusty 		type = get_wcaps_type(caps);
65918382eadSSubhransu S. Prusty 
66018382eadSSubhransu S. Prusty 		if (!(caps & AC_WCAP_DIGITAL))
66118382eadSSubhransu S. Prusty 			continue;
66218382eadSSubhransu S. Prusty 
66318382eadSSubhransu S. Prusty 		switch (type) {
66418382eadSSubhransu S. Prusty 
66518382eadSSubhransu S. Prusty 		case AC_WID_AUD_OUT:
66615b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_cvt(edev, nid);
66715b91447SSubhransu S. Prusty 			if (ret < 0)
66815b91447SSubhransu S. Prusty 				return ret;
66918382eadSSubhransu S. Prusty 			break;
67018382eadSSubhransu S. Prusty 
67118382eadSSubhransu S. Prusty 		case AC_WID_PIN:
67215b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_pin(edev, nid);
67315b91447SSubhransu S. Prusty 			if (ret < 0)
67415b91447SSubhransu S. Prusty 				return ret;
67518382eadSSubhransu S. Prusty 			break;
67618382eadSSubhransu S. Prusty 		}
67718382eadSSubhransu S. Prusty 	}
67818382eadSSubhransu S. Prusty 
67918382eadSSubhransu S. Prusty 	hdac->end_nid = nid;
68018382eadSSubhransu S. Prusty 
68115b91447SSubhransu S. Prusty 	if (!hdmi->num_pin || !hdmi->num_cvt)
68218382eadSSubhransu S. Prusty 		return -EIO;
68318382eadSSubhransu S. Prusty 
68415b91447SSubhransu S. Prusty 	return hdac_hdmi_init_dai_map(edev);
68518382eadSSubhransu S. Prusty }
68618382eadSSubhransu S. Prusty 
687b8a54545SSubhransu S. Prusty static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
688b8a54545SSubhransu S. Prusty {
689b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev = aptr;
690b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
691b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
692b8a54545SSubhransu S. Prusty 	struct snd_soc_codec *codec = edev->scodec;
693b8a54545SSubhransu S. Prusty 
694b8a54545SSubhransu S. Prusty 	/* Don't know how this mapping is derived */
695b8a54545SSubhransu S. Prusty 	hda_nid_t pin_nid = port + 0x04;
696b8a54545SSubhransu S. Prusty 
697b8a54545SSubhransu S. Prusty 	dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid);
698b8a54545SSubhransu S. Prusty 
699b8a54545SSubhransu S. Prusty 	/*
700b8a54545SSubhransu S. Prusty 	 * skip notification during system suspend (but not in runtime PM);
701b8a54545SSubhransu S. Prusty 	 * the state will be updated at resume. Also since the ELD and
702b8a54545SSubhransu S. Prusty 	 * connection states are updated in anyway at the end of the resume,
703b8a54545SSubhransu S. Prusty 	 * we can skip it when received during PM process.
704b8a54545SSubhransu S. Prusty 	 */
705b8a54545SSubhransu S. Prusty 	if (snd_power_get_state(codec->component.card->snd_card) !=
706b8a54545SSubhransu S. Prusty 			SNDRV_CTL_POWER_D0)
707b8a54545SSubhransu S. Prusty 		return;
708b8a54545SSubhransu S. Prusty 
709b8a54545SSubhransu S. Prusty 	if (atomic_read(&edev->hdac.in_pm))
710b8a54545SSubhransu S. Prusty 		return;
711b8a54545SSubhransu S. Prusty 
712b8a54545SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
713b8a54545SSubhransu S. Prusty 		if (pin->nid == pin_nid)
714b8a54545SSubhransu S. Prusty 			hdac_hdmi_present_sense(pin, 1);
715b8a54545SSubhransu S. Prusty 	}
716b8a54545SSubhransu S. Prusty }
717b8a54545SSubhransu S. Prusty 
718b8a54545SSubhransu S. Prusty static struct i915_audio_component_audio_ops aops = {
719b8a54545SSubhransu S. Prusty 	.pin_eld_notify	= hdac_hdmi_eld_notify_cb,
720b8a54545SSubhransu S. Prusty };
721b8a54545SSubhransu S. Prusty 
72218382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec)
72318382eadSSubhransu S. Prusty {
72418382eadSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
72518382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
72618382eadSSubhransu S. Prusty 	struct snd_soc_dapm_context *dapm =
72718382eadSSubhransu S. Prusty 		snd_soc_component_get_dapm(&codec->component);
728b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
729b8a54545SSubhransu S. Prusty 	int ret;
73018382eadSSubhransu S. Prusty 
73118382eadSSubhransu S. Prusty 	edev->scodec = codec;
73218382eadSSubhransu S. Prusty 
73318382eadSSubhransu S. Prusty 	create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
73418382eadSSubhransu S. Prusty 
735b8a54545SSubhransu S. Prusty 	aops.audio_ptr = edev;
736b8a54545SSubhransu S. Prusty 	ret = snd_hdac_i915_register_notifier(&aops);
737b8a54545SSubhransu S. Prusty 	if (ret < 0) {
738b8a54545SSubhransu S. Prusty 		dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n",
739b8a54545SSubhransu S. Prusty 				ret);
740b8a54545SSubhransu S. Prusty 		return ret;
741b8a54545SSubhransu S. Prusty 	}
742b8a54545SSubhransu S. Prusty 
743b8a54545SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head)
744b8a54545SSubhransu S. Prusty 		hdac_hdmi_present_sense(pin, 1);
745b8a54545SSubhransu S. Prusty 
74618382eadSSubhransu S. Prusty 	/* Imp: Store the card pointer in hda_codec */
74718382eadSSubhransu S. Prusty 	edev->card = dapm->card->snd_card;
74818382eadSSubhransu S. Prusty 
749e342ac08SSubhransu S. Prusty 	/*
750e342ac08SSubhransu S. Prusty 	 * hdac_device core already sets the state to active and calls
751e342ac08SSubhransu S. Prusty 	 * get_noresume. So enable runtime and set the device to suspend.
752e342ac08SSubhransu S. Prusty 	 */
753e342ac08SSubhransu S. Prusty 	pm_runtime_enable(&edev->hdac.dev);
754e342ac08SSubhransu S. Prusty 	pm_runtime_put(&edev->hdac.dev);
755e342ac08SSubhransu S. Prusty 	pm_runtime_suspend(&edev->hdac.dev);
756e342ac08SSubhransu S. Prusty 
757e342ac08SSubhransu S. Prusty 	return 0;
758e342ac08SSubhransu S. Prusty }
759e342ac08SSubhransu S. Prusty 
760e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec)
761e342ac08SSubhransu S. Prusty {
762e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
763e342ac08SSubhransu S. Prusty 
764e342ac08SSubhransu S. Prusty 	pm_runtime_disable(&edev->hdac.dev);
76518382eadSSubhransu S. Prusty 	return 0;
76618382eadSSubhransu S. Prusty }
76718382eadSSubhransu S. Prusty 
76818382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = {
76918382eadSSubhransu S. Prusty 	.probe		= hdmi_codec_probe,
770e342ac08SSubhransu S. Prusty 	.remove		= hdmi_codec_remove,
77118382eadSSubhransu S. Prusty 	.idle_bias_off	= true,
77218382eadSSubhransu S. Prusty };
77318382eadSSubhransu S. Prusty 
774b0362adbSSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = {
775b0362adbSSubhransu S. Prusty 	.startup = hdac_hdmi_pcm_open,
776b0362adbSSubhransu S. Prusty 	.shutdown = hdac_hdmi_pcm_close,
777b0362adbSSubhransu S. Prusty 	.hw_params = hdac_hdmi_set_hw_params,
778b0362adbSSubhransu S. Prusty 	.prepare = hdac_hdmi_playback_prepare,
779b0362adbSSubhransu S. Prusty 	.hw_free = hdac_hdmi_playback_cleanup,
780b0362adbSSubhransu S. Prusty };
781b0362adbSSubhransu S. Prusty 
78218382eadSSubhransu S. Prusty static struct snd_soc_dai_driver hdmi_dais[] = {
78318382eadSSubhransu S. Prusty 	{	.name = "intel-hdmi-hif1",
78418382eadSSubhransu S. Prusty 		.playback = {
78518382eadSSubhransu S. Prusty 			.stream_name = "hif1",
78618382eadSSubhransu S. Prusty 			.channels_min = 2,
78718382eadSSubhransu S. Prusty 			.channels_max = 2,
78818382eadSSubhransu S. Prusty 			.rates = SNDRV_PCM_RATE_32000 |
78918382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
79018382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
79118382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
79218382eadSSubhransu S. Prusty 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
79318382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S20_3LE |
79418382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S24_LE |
79518382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S32_LE,
79618382eadSSubhransu S. Prusty 
79718382eadSSubhransu S. Prusty 		},
798b0362adbSSubhransu S. Prusty 		.ops = &hdmi_dai_ops,
79918382eadSSubhransu S. Prusty 	},
80018382eadSSubhransu S. Prusty };
80118382eadSSubhransu S. Prusty 
80218382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
80318382eadSSubhransu S. Prusty {
80418382eadSSubhransu S. Prusty 	struct hdac_device *codec = &edev->hdac;
80518382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi_priv;
80618382eadSSubhransu S. Prusty 	int ret = 0;
80718382eadSSubhransu S. Prusty 
80818382eadSSubhransu S. Prusty 	hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
80918382eadSSubhransu S. Prusty 	if (hdmi_priv == NULL)
81018382eadSSubhransu S. Prusty 		return -ENOMEM;
81118382eadSSubhransu S. Prusty 
81218382eadSSubhransu S. Prusty 	edev->private_data = hdmi_priv;
81318382eadSSubhransu S. Prusty 
81418382eadSSubhransu S. Prusty 	dev_set_drvdata(&codec->dev, edev);
81518382eadSSubhransu S. Prusty 
81615b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->pin_list);
81715b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->cvt_list);
81815b91447SSubhransu S. Prusty 
81918382eadSSubhransu S. Prusty 	ret = hdac_hdmi_parse_and_map_nid(edev);
82018382eadSSubhransu S. Prusty 	if (ret < 0)
82118382eadSSubhransu S. Prusty 		return ret;
82218382eadSSubhransu S. Prusty 
82318382eadSSubhransu S. Prusty 	/* ASoC specific initialization */
82418382eadSSubhransu S. Prusty 	return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
82518382eadSSubhransu S. Prusty 			hdmi_dais, ARRAY_SIZE(hdmi_dais));
82618382eadSSubhransu S. Prusty }
82718382eadSSubhransu S. Prusty 
82818382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
82918382eadSSubhransu S. Prusty {
83015b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
83115b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin, *pin_next;
83215b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt, *cvt_next;
83315b91447SSubhransu S. Prusty 
83418382eadSSubhransu S. Prusty 	snd_soc_unregister_codec(&edev->hdac.dev);
83518382eadSSubhransu S. Prusty 
83615b91447SSubhransu S. Prusty 	list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
83715b91447SSubhransu S. Prusty 		list_del(&cvt->head);
83815b91447SSubhransu S. Prusty 		kfree(cvt);
83915b91447SSubhransu S. Prusty 	}
84015b91447SSubhransu S. Prusty 
84115b91447SSubhransu S. Prusty 	list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
84215b91447SSubhransu S. Prusty 		list_del(&pin->head);
84315b91447SSubhransu S. Prusty 		kfree(pin);
84415b91447SSubhransu S. Prusty 	}
84515b91447SSubhransu S. Prusty 
84618382eadSSubhransu S. Prusty 	return 0;
84718382eadSSubhransu S. Prusty }
84818382eadSSubhransu S. Prusty 
849e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM
850e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev)
851e342ac08SSubhransu S. Prusty {
852e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
853e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
85407f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
85507f083abSSubhransu S. Prusty 	int err;
856e342ac08SSubhransu S. Prusty 
857e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
858e342ac08SSubhransu S. Prusty 
85907f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
86007f083abSSubhransu S. Prusty 	if (!bus)
86107f083abSSubhransu S. Prusty 		return 0;
86207f083abSSubhransu S. Prusty 
863e342ac08SSubhransu S. Prusty 	/* Power down afg */
864e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
865e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
866e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
867e342ac08SSubhransu S. Prusty 
86807f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, false);
86907f083abSSubhransu S. Prusty 	if (err < 0) {
87007f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
87107f083abSSubhransu S. Prusty 		return err;
87207f083abSSubhransu S. Prusty 	}
87307f083abSSubhransu S. Prusty 
874e342ac08SSubhransu S. Prusty 	return 0;
875e342ac08SSubhransu S. Prusty }
876e342ac08SSubhransu S. Prusty 
877e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev)
878e342ac08SSubhransu S. Prusty {
879e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
880e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
88107f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
88207f083abSSubhransu S. Prusty 	int err;
883e342ac08SSubhransu S. Prusty 
884e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
885e342ac08SSubhransu S. Prusty 
88607f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
88707f083abSSubhransu S. Prusty 	if (!bus)
88807f083abSSubhransu S. Prusty 		return 0;
88907f083abSSubhransu S. Prusty 
89007f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, true);
89107f083abSSubhransu S. Prusty 	if (err < 0) {
89207f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
89307f083abSSubhransu S. Prusty 		return err;
89407f083abSSubhransu S. Prusty 	}
89507f083abSSubhransu S. Prusty 
896e342ac08SSubhransu S. Prusty 	/* Power up afg */
897e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
898e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
899e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
900e342ac08SSubhransu S. Prusty 
901e342ac08SSubhransu S. Prusty 	return 0;
902e342ac08SSubhransu S. Prusty }
903e342ac08SSubhransu S. Prusty #else
904e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL
905e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL
906e342ac08SSubhransu S. Prusty #endif
907e342ac08SSubhransu S. Prusty 
908e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = {
909e342ac08SSubhransu S. Prusty 	SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
910e342ac08SSubhransu S. Prusty };
911e342ac08SSubhransu S. Prusty 
91218382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = {
91318382eadSSubhransu S. Prusty 	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
91418382eadSSubhransu S. Prusty 	{}
91518382eadSSubhransu S. Prusty };
91618382eadSSubhransu S. Prusty 
91718382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
91818382eadSSubhransu S. Prusty 
91918382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = {
92018382eadSSubhransu S. Prusty 	. hdac = {
92118382eadSSubhransu S. Prusty 		.driver = {
92218382eadSSubhransu S. Prusty 			.name   = "HDMI HDA Codec",
923e342ac08SSubhransu S. Prusty 			.pm = &hdac_hdmi_pm,
92418382eadSSubhransu S. Prusty 		},
92518382eadSSubhransu S. Prusty 		.id_table       = hdmi_list,
92618382eadSSubhransu S. Prusty 	},
92718382eadSSubhransu S. Prusty 	.probe          = hdac_hdmi_dev_probe,
92818382eadSSubhransu S. Prusty 	.remove         = hdac_hdmi_dev_remove,
92918382eadSSubhransu S. Prusty };
93018382eadSSubhransu S. Prusty 
93118382eadSSubhransu S. Prusty static int __init hdmi_init(void)
93218382eadSSubhransu S. Prusty {
93318382eadSSubhransu S. Prusty 	return snd_hda_ext_driver_register(&hdmi_driver);
93418382eadSSubhransu S. Prusty }
93518382eadSSubhransu S. Prusty 
93618382eadSSubhransu S. Prusty static void __exit hdmi_exit(void)
93718382eadSSubhransu S. Prusty {
93818382eadSSubhransu S. Prusty 	snd_hda_ext_driver_unregister(&hdmi_driver);
93918382eadSSubhransu S. Prusty }
94018382eadSSubhransu S. Prusty 
94118382eadSSubhransu S. Prusty module_init(hdmi_init);
94218382eadSSubhransu S. Prusty module_exit(hdmi_exit);
94318382eadSSubhransu S. Prusty 
94418382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2");
94518382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec");
94618382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
94718382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
948