xref: /openbmc/linux/sound/soc/codecs/hdac_hdmi.c (revision 17a42c4500b05a6af4c32eb8e9cfc44bab945d1f)
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 
33*17a42c45SSubhransu S. Prusty #define NAME_SIZE	32
34*17a42c45SSubhransu 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 
44918382eadSSubhransu S. Prusty static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
45018382eadSSubhransu S. Prusty 				enum snd_soc_dapm_type id,
45118382eadSSubhransu S. Prusty 				const char *wname, const char *stream)
45218382eadSSubhransu S. Prusty {
45318382eadSSubhransu S. Prusty 	w->id = id;
45418382eadSSubhransu S. Prusty 	w->name = wname;
45518382eadSSubhransu S. Prusty 	w->sname = stream;
45618382eadSSubhransu S. Prusty 	w->reg = SND_SOC_NOPM;
45718382eadSSubhransu S. Prusty 	w->shift = 0;
45818382eadSSubhransu S. Prusty 	w->kcontrol_news = NULL;
45918382eadSSubhransu S. Prusty 	w->num_kcontrols = 0;
46018382eadSSubhransu S. Prusty 	w->priv = NULL;
46118382eadSSubhransu S. Prusty }
46218382eadSSubhransu S. Prusty 
46318382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
46418382eadSSubhransu S. Prusty 		const char *sink, const char *control, const char *src)
46518382eadSSubhransu S. Prusty {
46618382eadSSubhransu S. Prusty 	route->sink = sink;
46718382eadSSubhransu S. Prusty 	route->source = src;
46818382eadSSubhransu S. Prusty 	route->control = control;
46918382eadSSubhransu S. Prusty 	route->connected = NULL;
47018382eadSSubhransu S. Prusty }
47118382eadSSubhransu S. Prusty 
47218382eadSSubhransu S. Prusty static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
47318382eadSSubhransu S. Prusty 					struct hdac_hdmi_dai_pin_map *dai_map)
47418382eadSSubhransu S. Prusty {
47518382eadSSubhransu S. Prusty 	struct snd_soc_dapm_route route[1];
47618382eadSSubhransu S. Prusty 	struct snd_soc_dapm_widget widgets[2] = { {0} };
47718382eadSSubhransu S. Prusty 
47818382eadSSubhransu S. Prusty 	memset(&route, 0, sizeof(route));
47918382eadSSubhransu S. Prusty 
48018382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
48118382eadSSubhransu S. Prusty 			"hif1 Output", NULL);
48218382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
48318382eadSSubhransu S. Prusty 			"Coverter 1", "hif1");
48418382eadSSubhransu S. Prusty 
48518382eadSSubhransu S. Prusty 	hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
48618382eadSSubhransu S. Prusty 
48718382eadSSubhransu S. Prusty 	snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
48818382eadSSubhransu S. Prusty 	snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
48918382eadSSubhransu S. Prusty }
49018382eadSSubhransu S. Prusty 
49115b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
49218382eadSSubhransu S. Prusty {
49315b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
49415b91447SSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
49515b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
49615b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
49718382eadSSubhransu S. Prusty 
49815b91447SSubhransu S. Prusty 	if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
49915b91447SSubhransu S. Prusty 		return -EINVAL;
50018382eadSSubhransu S. Prusty 
50115b91447SSubhransu S. Prusty 	/*
50215b91447SSubhransu S. Prusty 	 * Currently on board only 1 pin and 1 converter is enabled for
50315b91447SSubhransu S. Prusty 	 * simplification, more will be added eventually
50415b91447SSubhransu S. Prusty 	 * So using fixed map for dai_id:pin:cvt
50515b91447SSubhransu S. Prusty 	 */
50615b91447SSubhransu S. Prusty 	cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
50715b91447SSubhransu S. Prusty 	pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
50818382eadSSubhransu S. Prusty 
50915b91447SSubhransu S. Prusty 	dai_map->dai_id = 0;
51015b91447SSubhransu S. Prusty 	dai_map->pin = pin;
51115b91447SSubhransu S. Prusty 
51215b91447SSubhransu S. Prusty 	dai_map->cvt = cvt;
51318382eadSSubhransu S. Prusty 
51418382eadSSubhransu S. Prusty 	/* Enable out path for this pin widget */
51515b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
51618382eadSSubhransu S. Prusty 			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
51718382eadSSubhransu S. Prusty 
51818382eadSSubhransu S. Prusty 	/* Enable transmission */
51915b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
52018382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_1, 1);
52118382eadSSubhransu S. Prusty 
52218382eadSSubhransu S. Prusty 	/* Category Code (CC) to zero */
52315b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
52418382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_2, 0);
52518382eadSSubhransu S. Prusty 
52615b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
52718382eadSSubhransu S. Prusty 			AC_VERB_SET_CONNECT_SEL, 0);
52818382eadSSubhransu S. Prusty 
52915b91447SSubhransu S. Prusty 	return 0;
53015b91447SSubhransu S. Prusty }
53115b91447SSubhransu S. Prusty 
53215b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
53315b91447SSubhransu S. Prusty {
53415b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
53515b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
53615b91447SSubhransu S. Prusty 
53715b91447SSubhransu S. Prusty 	cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
53815b91447SSubhransu S. Prusty 	if (!cvt)
53915b91447SSubhransu S. Prusty 		return -ENOMEM;
54015b91447SSubhransu S. Prusty 
54115b91447SSubhransu S. Prusty 	cvt->nid = nid;
54215b91447SSubhransu S. Prusty 
54315b91447SSubhransu S. Prusty 	list_add_tail(&cvt->head, &hdmi->cvt_list);
54415b91447SSubhransu S. Prusty 	hdmi->num_cvt++;
54515b91447SSubhransu S. Prusty 
54615b91447SSubhransu S. Prusty 	return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
54715b91447SSubhransu S. Prusty }
54815b91447SSubhransu S. Prusty 
549b8a54545SSubhransu S. Prusty static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
550b8a54545SSubhransu S. Prusty {
551b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev = pin->edev;
552b8a54545SSubhransu S. Prusty 	int val;
553b8a54545SSubhransu S. Prusty 
554b8a54545SSubhransu S. Prusty 	if (!edev)
555b8a54545SSubhransu S. Prusty 		return;
556b8a54545SSubhransu S. Prusty 
557b8a54545SSubhransu S. Prusty 	pin->repoll_count = repoll;
558b8a54545SSubhransu S. Prusty 
559b8a54545SSubhransu S. Prusty 	pm_runtime_get_sync(&edev->hdac.dev);
560b8a54545SSubhransu S. Prusty 	val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0,
561b8a54545SSubhransu S. Prusty 					AC_VERB_GET_PIN_SENSE, 0);
562b8a54545SSubhransu S. Prusty 
563b8a54545SSubhransu S. Prusty 	dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n",
564b8a54545SSubhransu S. Prusty 						val, pin->nid);
565b8a54545SSubhransu S. Prusty 
566b8a54545SSubhransu S. Prusty 	pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE);
567b8a54545SSubhransu S. Prusty 	pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV);
568b8a54545SSubhransu S. Prusty 
569b8a54545SSubhransu S. Prusty 	if (!pin->eld.monitor_present || !pin->eld.eld_valid) {
570b8a54545SSubhransu S. Prusty 
571b8a54545SSubhransu S. Prusty 		dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n",
572b8a54545SSubhransu S. Prusty 						__func__, pin->nid);
573b8a54545SSubhransu S. Prusty 		goto put_hdac_device;
574b8a54545SSubhransu S. Prusty 	}
575b8a54545SSubhransu S. Prusty 
576b8a54545SSubhransu S. Prusty 	if (pin->eld.monitor_present && pin->eld.eld_valid) {
577b8a54545SSubhransu S. Prusty 		/* TODO: use i915 component for reading ELD later */
578b8a54545SSubhransu S. Prusty 		if (hdac_hdmi_get_eld(&edev->hdac, pin->nid,
579b8a54545SSubhransu S. Prusty 				pin->eld.eld_buffer,
580b8a54545SSubhransu S. Prusty 				&pin->eld.eld_size) == 0) {
581b8a54545SSubhransu S. Prusty 
582b8a54545SSubhransu S. Prusty 			print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET,
583b8a54545SSubhransu S. Prusty 					pin->eld.eld_buffer, pin->eld.eld_size);
584b8a54545SSubhransu S. Prusty 		} else {
585b8a54545SSubhransu S. Prusty 			pin->eld.monitor_present = false;
586b8a54545SSubhransu S. Prusty 			pin->eld.eld_valid = false;
587b8a54545SSubhransu S. Prusty 		}
588b8a54545SSubhransu S. Prusty 	}
589b8a54545SSubhransu S. Prusty 
590b8a54545SSubhransu S. Prusty 	/*
591b8a54545SSubhransu S. Prusty 	 * Sometimes the pin_sense may present invalid monitor
592b8a54545SSubhransu S. Prusty 	 * present and eld_valid. If ELD data is not valid, loop few
593b8a54545SSubhransu S. Prusty 	 * more times to get correct pin sense and valid ELD.
594b8a54545SSubhransu S. Prusty 	 */
595b8a54545SSubhransu S. Prusty 	if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll)
596b8a54545SSubhransu S. Prusty 		schedule_delayed_work(&pin->work, msecs_to_jiffies(300));
597b8a54545SSubhransu S. Prusty 
598b8a54545SSubhransu S. Prusty put_hdac_device:
599b8a54545SSubhransu S. Prusty 	pm_runtime_put_sync(&edev->hdac.dev);
600b8a54545SSubhransu S. Prusty }
601b8a54545SSubhransu S. Prusty 
602b8a54545SSubhransu S. Prusty static void hdac_hdmi_repoll_eld(struct work_struct *work)
603b8a54545SSubhransu S. Prusty {
604b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin =
605b8a54545SSubhransu S. Prusty 		container_of(to_delayed_work(work), struct hdac_hdmi_pin, work);
606b8a54545SSubhransu S. Prusty 
607b8a54545SSubhransu S. Prusty 	/* picked from legacy HDA driver */
608b8a54545SSubhransu S. Prusty 	if (pin->repoll_count++ > 6)
609b8a54545SSubhransu S. Prusty 		pin->repoll_count = 0;
610b8a54545SSubhransu S. Prusty 
611b8a54545SSubhransu S. Prusty 	hdac_hdmi_present_sense(pin, pin->repoll_count);
612b8a54545SSubhransu S. Prusty }
613b8a54545SSubhransu S. Prusty 
61415b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
61515b91447SSubhransu S. Prusty {
61615b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
61715b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
61815b91447SSubhransu S. Prusty 
61915b91447SSubhransu S. Prusty 	pin = kzalloc(sizeof(*pin), GFP_KERNEL);
62015b91447SSubhransu S. Prusty 	if (!pin)
62115b91447SSubhransu S. Prusty 		return -ENOMEM;
62215b91447SSubhransu S. Prusty 
62315b91447SSubhransu S. Prusty 	pin->nid = nid;
62415b91447SSubhransu S. Prusty 
62515b91447SSubhransu S. Prusty 	list_add_tail(&pin->head, &hdmi->pin_list);
62615b91447SSubhransu S. Prusty 	hdmi->num_pin++;
62715b91447SSubhransu S. Prusty 
628b8a54545SSubhransu S. Prusty 	pin->edev = edev;
629b8a54545SSubhransu S. Prusty 	INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
630b8a54545SSubhransu S. Prusty 
63115b91447SSubhransu S. Prusty 	return 0;
63218382eadSSubhransu S. Prusty }
63318382eadSSubhransu S. Prusty 
634211caab7SSubhransu S. Prusty #define INTEL_VENDOR_NID 0x08
635211caab7SSubhransu S. Prusty #define INTEL_GET_VENDOR_VERB 0xf81
636211caab7SSubhransu S. Prusty #define INTEL_SET_VENDOR_VERB 0x781
637211caab7SSubhransu S. Prusty #define INTEL_EN_DP12			0x02 /* enable DP 1.2 features */
638211caab7SSubhransu S. Prusty #define INTEL_EN_ALL_PIN_CVTS	0x01 /* enable 2nd & 3rd pins and convertors */
639211caab7SSubhransu S. Prusty 
640211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
641211caab7SSubhransu S. Prusty {
642211caab7SSubhransu S. Prusty 	unsigned int vendor_param;
643211caab7SSubhransu S. Prusty 
644211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
645211caab7SSubhransu S. Prusty 				INTEL_GET_VENDOR_VERB, 0);
646211caab7SSubhransu S. Prusty 	if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
647211caab7SSubhransu S. Prusty 		return;
648211caab7SSubhransu S. Prusty 
649211caab7SSubhransu S. Prusty 	vendor_param |= INTEL_EN_ALL_PIN_CVTS;
650211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
651211caab7SSubhransu S. Prusty 				INTEL_SET_VENDOR_VERB, vendor_param);
652211caab7SSubhransu S. Prusty 	if (vendor_param == -1)
653211caab7SSubhransu S. Prusty 		return;
654211caab7SSubhransu S. Prusty }
655211caab7SSubhransu S. Prusty 
656211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
657211caab7SSubhransu S. Prusty {
658211caab7SSubhransu S. Prusty 	unsigned int vendor_param;
659211caab7SSubhransu S. Prusty 
660211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
661211caab7SSubhransu S. Prusty 				INTEL_GET_VENDOR_VERB, 0);
662211caab7SSubhransu S. Prusty 	if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
663211caab7SSubhransu S. Prusty 		return;
664211caab7SSubhransu S. Prusty 
665211caab7SSubhransu S. Prusty 	/* enable DP1.2 mode */
666211caab7SSubhransu S. Prusty 	vendor_param |= INTEL_EN_DP12;
667211caab7SSubhransu S. Prusty 	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
668211caab7SSubhransu S. Prusty 				INTEL_SET_VENDOR_VERB, vendor_param);
669211caab7SSubhransu S. Prusty 	if (vendor_param == -1)
670211caab7SSubhransu S. Prusty 		return;
671211caab7SSubhransu S. Prusty 
672211caab7SSubhransu S. Prusty }
673211caab7SSubhransu S. Prusty 
674*17a42c45SSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = {
675*17a42c45SSubhransu S. Prusty 	.startup = hdac_hdmi_pcm_open,
676*17a42c45SSubhransu S. Prusty 	.shutdown = hdac_hdmi_pcm_close,
677*17a42c45SSubhransu S. Prusty 	.hw_params = hdac_hdmi_set_hw_params,
678*17a42c45SSubhransu S. Prusty 	.prepare = hdac_hdmi_playback_prepare,
679*17a42c45SSubhransu S. Prusty 	.hw_free = hdac_hdmi_playback_cleanup,
680*17a42c45SSubhransu S. Prusty };
681*17a42c45SSubhransu S. Prusty 
682*17a42c45SSubhransu S. Prusty /*
683*17a42c45SSubhransu S. Prusty  * Each converter can support a stream independently. So a dai is created
684*17a42c45SSubhransu S. Prusty  * based on the number of converter queried.
685*17a42c45SSubhransu S. Prusty  */
686*17a42c45SSubhransu S. Prusty static int hdac_hdmi_create_dais(struct hdac_device *hdac,
687*17a42c45SSubhransu S. Prusty 		struct snd_soc_dai_driver **dais,
688*17a42c45SSubhransu S. Prusty 		struct hdac_hdmi_priv *hdmi, int num_dais)
689*17a42c45SSubhransu S. Prusty {
690*17a42c45SSubhransu S. Prusty 	struct snd_soc_dai_driver *hdmi_dais;
691*17a42c45SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
692*17a42c45SSubhransu S. Prusty 	char name[NAME_SIZE], dai_name[NAME_SIZE];
693*17a42c45SSubhransu S. Prusty 	int i = 0;
694*17a42c45SSubhransu S. Prusty 	u32 rates, bps;
695*17a42c45SSubhransu S. Prusty 	unsigned int rate_max = 384000, rate_min = 8000;
696*17a42c45SSubhransu S. Prusty 	u64 formats;
697*17a42c45SSubhransu S. Prusty 	int ret;
698*17a42c45SSubhransu S. Prusty 
699*17a42c45SSubhransu S. Prusty 	hdmi_dais = devm_kzalloc(&hdac->dev,
700*17a42c45SSubhransu S. Prusty 			(sizeof(*hdmi_dais) * num_dais),
701*17a42c45SSubhransu S. Prusty 			GFP_KERNEL);
702*17a42c45SSubhransu S. Prusty 	if (!hdmi_dais)
703*17a42c45SSubhransu S. Prusty 		return -ENOMEM;
704*17a42c45SSubhransu S. Prusty 
705*17a42c45SSubhransu S. Prusty 	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
706*17a42c45SSubhransu S. Prusty 		ret = snd_hdac_query_supported_pcm(hdac, cvt->nid,
707*17a42c45SSubhransu S. Prusty 					&rates,	&formats, &bps);
708*17a42c45SSubhransu S. Prusty 		if (ret)
709*17a42c45SSubhransu S. Prusty 			return ret;
710*17a42c45SSubhransu S. Prusty 
711*17a42c45SSubhransu S. Prusty 		sprintf(dai_name, "intel-hdmi-hifi%d", i+1);
712*17a42c45SSubhransu S. Prusty 		hdmi_dais[i].name = devm_kstrdup(&hdac->dev,
713*17a42c45SSubhransu S. Prusty 					dai_name, GFP_KERNEL);
714*17a42c45SSubhransu S. Prusty 
715*17a42c45SSubhransu S. Prusty 		if (!hdmi_dais[i].name)
716*17a42c45SSubhransu S. Prusty 			return -ENOMEM;
717*17a42c45SSubhransu S. Prusty 
718*17a42c45SSubhransu S. Prusty 		snprintf(name, sizeof(name), "hifi%d", i+1);
719*17a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.stream_name =
720*17a42c45SSubhransu S. Prusty 				devm_kstrdup(&hdac->dev, name, GFP_KERNEL);
721*17a42c45SSubhransu S. Prusty 		if (!hdmi_dais[i].playback.stream_name)
722*17a42c45SSubhransu S. Prusty 			return -ENOMEM;
723*17a42c45SSubhransu S. Prusty 
724*17a42c45SSubhransu S. Prusty 		/*
725*17a42c45SSubhransu S. Prusty 		 * Set caps based on capability queried from the converter.
726*17a42c45SSubhransu S. Prusty 		 * It will be constrained runtime based on ELD queried.
727*17a42c45SSubhransu S. Prusty 		 */
728*17a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.formats = formats;
729*17a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.rates = rates;
730*17a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.rate_max = rate_max;
731*17a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.rate_min = rate_min;
732*17a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.channels_min = 2;
733*17a42c45SSubhransu S. Prusty 		hdmi_dais[i].playback.channels_max = 2;
734*17a42c45SSubhransu S. Prusty 		hdmi_dais[i].ops = &hdmi_dai_ops;
735*17a42c45SSubhransu S. Prusty 
736*17a42c45SSubhransu S. Prusty 		i++;
737*17a42c45SSubhransu S. Prusty 	}
738*17a42c45SSubhransu S. Prusty 
739*17a42c45SSubhransu S. Prusty 	*dais = hdmi_dais;
740*17a42c45SSubhransu S. Prusty 
741*17a42c45SSubhransu S. Prusty 	return 0;
742*17a42c45SSubhransu S. Prusty }
743*17a42c45SSubhransu S. Prusty 
74418382eadSSubhransu S. Prusty /*
74518382eadSSubhransu S. Prusty  * Parse all nodes and store the cvt/pin nids in array
74618382eadSSubhransu S. Prusty  * Add one time initialization for pin and cvt widgets
74718382eadSSubhransu S. Prusty  */
748*17a42c45SSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
749*17a42c45SSubhransu S. Prusty 		struct snd_soc_dai_driver **dais, int *num_dais)
75018382eadSSubhransu S. Prusty {
75118382eadSSubhransu S. Prusty 	hda_nid_t nid;
7523c83ac23SSudip Mukherjee 	int i, num_nodes;
75318382eadSSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
75418382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
75515b91447SSubhransu S. Prusty 	int ret;
75618382eadSSubhransu S. Prusty 
757211caab7SSubhransu S. Prusty 	hdac_hdmi_skl_enable_all_pins(hdac);
758211caab7SSubhransu S. Prusty 	hdac_hdmi_skl_enable_dp12(hdac);
759211caab7SSubhransu S. Prusty 
7603c83ac23SSudip Mukherjee 	num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
761541140d4SSubhransu S. Prusty 	if (!nid || num_nodes <= 0) {
76218382eadSSubhransu S. Prusty 		dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
76318382eadSSubhransu S. Prusty 		return -EINVAL;
76418382eadSSubhransu S. Prusty 	}
76518382eadSSubhransu S. Prusty 
7663c83ac23SSudip Mukherjee 	hdac->num_nodes = num_nodes;
76718382eadSSubhransu S. Prusty 	hdac->start_nid = nid;
76818382eadSSubhransu S. Prusty 
76918382eadSSubhransu S. Prusty 	for (i = 0; i < hdac->num_nodes; i++, nid++) {
77018382eadSSubhransu S. Prusty 		unsigned int caps;
77118382eadSSubhransu S. Prusty 		unsigned int type;
77218382eadSSubhransu S. Prusty 
77318382eadSSubhransu S. Prusty 		caps = get_wcaps(hdac, nid);
77418382eadSSubhransu S. Prusty 		type = get_wcaps_type(caps);
77518382eadSSubhransu S. Prusty 
77618382eadSSubhransu S. Prusty 		if (!(caps & AC_WCAP_DIGITAL))
77718382eadSSubhransu S. Prusty 			continue;
77818382eadSSubhransu S. Prusty 
77918382eadSSubhransu S. Prusty 		switch (type) {
78018382eadSSubhransu S. Prusty 
78118382eadSSubhransu S. Prusty 		case AC_WID_AUD_OUT:
78215b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_cvt(edev, nid);
78315b91447SSubhransu S. Prusty 			if (ret < 0)
78415b91447SSubhransu S. Prusty 				return ret;
78518382eadSSubhransu S. Prusty 			break;
78618382eadSSubhransu S. Prusty 
78718382eadSSubhransu S. Prusty 		case AC_WID_PIN:
78815b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_pin(edev, nid);
78915b91447SSubhransu S. Prusty 			if (ret < 0)
79015b91447SSubhransu S. Prusty 				return ret;
79118382eadSSubhransu S. Prusty 			break;
79218382eadSSubhransu S. Prusty 		}
79318382eadSSubhransu S. Prusty 	}
79418382eadSSubhransu S. Prusty 
79518382eadSSubhransu S. Prusty 	hdac->end_nid = nid;
79618382eadSSubhransu S. Prusty 
79715b91447SSubhransu S. Prusty 	if (!hdmi->num_pin || !hdmi->num_cvt)
79818382eadSSubhransu S. Prusty 		return -EIO;
79918382eadSSubhransu S. Prusty 
800*17a42c45SSubhransu S. Prusty 	ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt);
801*17a42c45SSubhransu S. Prusty 	if (ret) {
802*17a42c45SSubhransu S. Prusty 		dev_err(&hdac->dev, "Failed to create dais with err: %d\n",
803*17a42c45SSubhransu S. Prusty 							ret);
804*17a42c45SSubhransu S. Prusty 		return ret;
805*17a42c45SSubhransu S. Prusty 	}
806*17a42c45SSubhransu S. Prusty 
807*17a42c45SSubhransu S. Prusty 	*num_dais = hdmi->num_cvt;
808*17a42c45SSubhransu S. Prusty 
80915b91447SSubhransu S. Prusty 	return hdac_hdmi_init_dai_map(edev);
81018382eadSSubhransu S. Prusty }
81118382eadSSubhransu S. Prusty 
812b8a54545SSubhransu S. Prusty static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
813b8a54545SSubhransu S. Prusty {
814b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev = aptr;
815b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
816b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
817b8a54545SSubhransu S. Prusty 	struct snd_soc_codec *codec = edev->scodec;
818b8a54545SSubhransu S. Prusty 
819b8a54545SSubhransu S. Prusty 	/* Don't know how this mapping is derived */
820b8a54545SSubhransu S. Prusty 	hda_nid_t pin_nid = port + 0x04;
821b8a54545SSubhransu S. Prusty 
822b8a54545SSubhransu S. Prusty 	dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid);
823b8a54545SSubhransu S. Prusty 
824b8a54545SSubhransu S. Prusty 	/*
825b8a54545SSubhransu S. Prusty 	 * skip notification during system suspend (but not in runtime PM);
826b8a54545SSubhransu S. Prusty 	 * the state will be updated at resume. Also since the ELD and
827b8a54545SSubhransu S. Prusty 	 * connection states are updated in anyway at the end of the resume,
828b8a54545SSubhransu S. Prusty 	 * we can skip it when received during PM process.
829b8a54545SSubhransu S. Prusty 	 */
830b8a54545SSubhransu S. Prusty 	if (snd_power_get_state(codec->component.card->snd_card) !=
831b8a54545SSubhransu S. Prusty 			SNDRV_CTL_POWER_D0)
832b8a54545SSubhransu S. Prusty 		return;
833b8a54545SSubhransu S. Prusty 
834b8a54545SSubhransu S. Prusty 	if (atomic_read(&edev->hdac.in_pm))
835b8a54545SSubhransu S. Prusty 		return;
836b8a54545SSubhransu S. Prusty 
837b8a54545SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
838b8a54545SSubhransu S. Prusty 		if (pin->nid == pin_nid)
839b8a54545SSubhransu S. Prusty 			hdac_hdmi_present_sense(pin, 1);
840b8a54545SSubhransu S. Prusty 	}
841b8a54545SSubhransu S. Prusty }
842b8a54545SSubhransu S. Prusty 
843b8a54545SSubhransu S. Prusty static struct i915_audio_component_audio_ops aops = {
844b8a54545SSubhransu S. Prusty 	.pin_eld_notify	= hdac_hdmi_eld_notify_cb,
845b8a54545SSubhransu S. Prusty };
846b8a54545SSubhransu S. Prusty 
84718382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec)
84818382eadSSubhransu S. Prusty {
84918382eadSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
85018382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
85118382eadSSubhransu S. Prusty 	struct snd_soc_dapm_context *dapm =
85218382eadSSubhransu S. Prusty 		snd_soc_component_get_dapm(&codec->component);
853b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
854b8a54545SSubhransu S. Prusty 	int ret;
85518382eadSSubhransu S. Prusty 
85618382eadSSubhransu S. Prusty 	edev->scodec = codec;
85718382eadSSubhransu S. Prusty 
85818382eadSSubhransu S. Prusty 	create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
85918382eadSSubhransu S. Prusty 
860b8a54545SSubhransu S. Prusty 	aops.audio_ptr = edev;
861b8a54545SSubhransu S. Prusty 	ret = snd_hdac_i915_register_notifier(&aops);
862b8a54545SSubhransu S. Prusty 	if (ret < 0) {
863b8a54545SSubhransu S. Prusty 		dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n",
864b8a54545SSubhransu S. Prusty 				ret);
865b8a54545SSubhransu S. Prusty 		return ret;
866b8a54545SSubhransu S. Prusty 	}
867b8a54545SSubhransu S. Prusty 
868b8a54545SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head)
869b8a54545SSubhransu S. Prusty 		hdac_hdmi_present_sense(pin, 1);
870b8a54545SSubhransu S. Prusty 
87118382eadSSubhransu S. Prusty 	/* Imp: Store the card pointer in hda_codec */
87218382eadSSubhransu S. Prusty 	edev->card = dapm->card->snd_card;
87318382eadSSubhransu S. Prusty 
874e342ac08SSubhransu S. Prusty 	/*
875e342ac08SSubhransu S. Prusty 	 * hdac_device core already sets the state to active and calls
876e342ac08SSubhransu S. Prusty 	 * get_noresume. So enable runtime and set the device to suspend.
877e342ac08SSubhransu S. Prusty 	 */
878e342ac08SSubhransu S. Prusty 	pm_runtime_enable(&edev->hdac.dev);
879e342ac08SSubhransu S. Prusty 	pm_runtime_put(&edev->hdac.dev);
880e342ac08SSubhransu S. Prusty 	pm_runtime_suspend(&edev->hdac.dev);
881e342ac08SSubhransu S. Prusty 
882e342ac08SSubhransu S. Prusty 	return 0;
883e342ac08SSubhransu S. Prusty }
884e342ac08SSubhransu S. Prusty 
885e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec)
886e342ac08SSubhransu S. Prusty {
887e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
888e342ac08SSubhransu S. Prusty 
889e342ac08SSubhransu S. Prusty 	pm_runtime_disable(&edev->hdac.dev);
89018382eadSSubhransu S. Prusty 	return 0;
89118382eadSSubhransu S. Prusty }
89218382eadSSubhransu S. Prusty 
89318382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = {
89418382eadSSubhransu S. Prusty 	.probe		= hdmi_codec_probe,
895e342ac08SSubhransu S. Prusty 	.remove		= hdmi_codec_remove,
89618382eadSSubhransu S. Prusty 	.idle_bias_off	= true,
89718382eadSSubhransu S. Prusty };
89818382eadSSubhransu S. Prusty 
89918382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
90018382eadSSubhransu S. Prusty {
90118382eadSSubhransu S. Prusty 	struct hdac_device *codec = &edev->hdac;
90218382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi_priv;
903*17a42c45SSubhransu S. Prusty 	struct snd_soc_dai_driver *hdmi_dais = NULL;
904*17a42c45SSubhransu S. Prusty 	int num_dais = 0;
90518382eadSSubhransu S. Prusty 	int ret = 0;
90618382eadSSubhransu S. Prusty 
90718382eadSSubhransu S. Prusty 	hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
90818382eadSSubhransu S. Prusty 	if (hdmi_priv == NULL)
90918382eadSSubhransu S. Prusty 		return -ENOMEM;
91018382eadSSubhransu S. Prusty 
91118382eadSSubhransu S. Prusty 	edev->private_data = hdmi_priv;
91218382eadSSubhransu S. Prusty 
91318382eadSSubhransu S. Prusty 	dev_set_drvdata(&codec->dev, edev);
91418382eadSSubhransu S. Prusty 
91515b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->pin_list);
91615b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->cvt_list);
91715b91447SSubhransu S. Prusty 
918*17a42c45SSubhransu S. Prusty 	ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais);
919*17a42c45SSubhransu S. Prusty 	if (ret < 0) {
920*17a42c45SSubhransu S. Prusty 		dev_err(&codec->dev,
921*17a42c45SSubhransu S. Prusty 			"Failed in parse and map nid with err: %d\n", ret);
92218382eadSSubhransu S. Prusty 		return ret;
923*17a42c45SSubhransu S. Prusty 	}
92418382eadSSubhransu S. Prusty 
92518382eadSSubhransu S. Prusty 	/* ASoC specific initialization */
92618382eadSSubhransu S. Prusty 	return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
927*17a42c45SSubhransu S. Prusty 			hdmi_dais, num_dais);
92818382eadSSubhransu S. Prusty }
92918382eadSSubhransu S. Prusty 
93018382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
93118382eadSSubhransu S. Prusty {
93215b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
93315b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin, *pin_next;
93415b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt, *cvt_next;
93515b91447SSubhransu S. Prusty 
93618382eadSSubhransu S. Prusty 	snd_soc_unregister_codec(&edev->hdac.dev);
93718382eadSSubhransu S. Prusty 
93815b91447SSubhransu S. Prusty 	list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
93915b91447SSubhransu S. Prusty 		list_del(&cvt->head);
94015b91447SSubhransu S. Prusty 		kfree(cvt);
94115b91447SSubhransu S. Prusty 	}
94215b91447SSubhransu S. Prusty 
94315b91447SSubhransu S. Prusty 	list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
94415b91447SSubhransu S. Prusty 		list_del(&pin->head);
94515b91447SSubhransu S. Prusty 		kfree(pin);
94615b91447SSubhransu S. Prusty 	}
94715b91447SSubhransu S. Prusty 
94818382eadSSubhransu S. Prusty 	return 0;
94918382eadSSubhransu S. Prusty }
95018382eadSSubhransu S. Prusty 
951e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM
952e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev)
953e342ac08SSubhransu S. Prusty {
954e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
955e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
95607f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
95707f083abSSubhransu S. Prusty 	int err;
958e342ac08SSubhransu S. Prusty 
959e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
960e342ac08SSubhransu S. Prusty 
96107f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
96207f083abSSubhransu S. Prusty 	if (!bus)
96307f083abSSubhransu S. Prusty 		return 0;
96407f083abSSubhransu S. Prusty 
965e342ac08SSubhransu S. Prusty 	/* Power down afg */
966e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
967e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
968e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
969e342ac08SSubhransu S. Prusty 
97007f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, false);
97107f083abSSubhransu S. Prusty 	if (err < 0) {
97207f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
97307f083abSSubhransu S. Prusty 		return err;
97407f083abSSubhransu S. Prusty 	}
97507f083abSSubhransu S. Prusty 
976e342ac08SSubhransu S. Prusty 	return 0;
977e342ac08SSubhransu S. Prusty }
978e342ac08SSubhransu S. Prusty 
979e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev)
980e342ac08SSubhransu S. Prusty {
981e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
982e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
98307f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
98407f083abSSubhransu S. Prusty 	int err;
985e342ac08SSubhransu S. Prusty 
986e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
987e342ac08SSubhransu S. Prusty 
98807f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
98907f083abSSubhransu S. Prusty 	if (!bus)
99007f083abSSubhransu S. Prusty 		return 0;
99107f083abSSubhransu S. Prusty 
99207f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, true);
99307f083abSSubhransu S. Prusty 	if (err < 0) {
99407f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
99507f083abSSubhransu S. Prusty 		return err;
99607f083abSSubhransu S. Prusty 	}
99707f083abSSubhransu S. Prusty 
998e342ac08SSubhransu S. Prusty 	/* Power up afg */
999e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
1000e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
1001e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
1002e342ac08SSubhransu S. Prusty 
1003e342ac08SSubhransu S. Prusty 	return 0;
1004e342ac08SSubhransu S. Prusty }
1005e342ac08SSubhransu S. Prusty #else
1006e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL
1007e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL
1008e342ac08SSubhransu S. Prusty #endif
1009e342ac08SSubhransu S. Prusty 
1010e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = {
1011e342ac08SSubhransu S. Prusty 	SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
1012e342ac08SSubhransu S. Prusty };
1013e342ac08SSubhransu S. Prusty 
101418382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = {
101518382eadSSubhransu S. Prusty 	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
101618382eadSSubhransu S. Prusty 	{}
101718382eadSSubhransu S. Prusty };
101818382eadSSubhransu S. Prusty 
101918382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
102018382eadSSubhransu S. Prusty 
102118382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = {
102218382eadSSubhransu S. Prusty 	. hdac = {
102318382eadSSubhransu S. Prusty 		.driver = {
102418382eadSSubhransu S. Prusty 			.name   = "HDMI HDA Codec",
1025e342ac08SSubhransu S. Prusty 			.pm = &hdac_hdmi_pm,
102618382eadSSubhransu S. Prusty 		},
102718382eadSSubhransu S. Prusty 		.id_table       = hdmi_list,
102818382eadSSubhransu S. Prusty 	},
102918382eadSSubhransu S. Prusty 	.probe          = hdac_hdmi_dev_probe,
103018382eadSSubhransu S. Prusty 	.remove         = hdac_hdmi_dev_remove,
103118382eadSSubhransu S. Prusty };
103218382eadSSubhransu S. Prusty 
103318382eadSSubhransu S. Prusty static int __init hdmi_init(void)
103418382eadSSubhransu S. Prusty {
103518382eadSSubhransu S. Prusty 	return snd_hda_ext_driver_register(&hdmi_driver);
103618382eadSSubhransu S. Prusty }
103718382eadSSubhransu S. Prusty 
103818382eadSSubhransu S. Prusty static void __exit hdmi_exit(void)
103918382eadSSubhransu S. Prusty {
104018382eadSSubhransu S. Prusty 	snd_hda_ext_driver_unregister(&hdmi_driver);
104118382eadSSubhransu S. Prusty }
104218382eadSSubhransu S. Prusty 
104318382eadSSubhransu S. Prusty module_init(hdmi_init);
104418382eadSSubhransu S. Prusty module_exit(hdmi_exit);
104518382eadSSubhransu S. Prusty 
104618382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2");
104718382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec");
104818382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
104918382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
1050