xref: /openbmc/linux/sound/soc/codecs/hdac_hdmi.c (revision b8a54545b00cbf2aff743578c5c69aafdcde1d64)
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>
2518382eadSSubhransu S. Prusty #include <sound/pcm_params.h>
2618382eadSSubhransu S. Prusty #include <sound/soc.h>
2718382eadSSubhransu S. Prusty #include <sound/hdaudio_ext.h>
2807f083abSSubhransu S. Prusty #include <sound/hda_i915.h>
2918382eadSSubhransu S. Prusty #include "../../hda/local.h"
3018382eadSSubhransu S. Prusty 
31b0362adbSSubhransu S. Prusty #define AMP_OUT_MUTE		0xb080
32b0362adbSSubhransu S. Prusty #define AMP_OUT_UNMUTE		0xb000
3318382eadSSubhransu S. Prusty #define PIN_OUT			(AC_PINCTL_OUT_EN)
34b0362adbSSubhransu S. Prusty 
3518382eadSSubhransu S. Prusty #define HDA_MAX_CONNECTIONS     32
3618382eadSSubhransu S. Prusty 
37*b8a54545SSubhransu S. Prusty #define ELD_MAX_SIZE    256
38*b8a54545SSubhransu S. Prusty #define ELD_FIXED_BYTES	20
39*b8a54545SSubhransu S. Prusty 
4018382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params {
4118382eadSSubhransu S. Prusty 	unsigned int channels_min;
4218382eadSSubhransu S. Prusty 	unsigned int channels_max;
4318382eadSSubhransu S. Prusty 	u32 rates;
4418382eadSSubhransu S. Prusty 	u64 formats;
4518382eadSSubhransu S. Prusty 	unsigned int maxbps;
4618382eadSSubhransu S. Prusty };
4718382eadSSubhransu S. Prusty 
4818382eadSSubhransu S. Prusty struct hdac_hdmi_cvt {
4915b91447SSubhransu S. Prusty 	struct list_head head;
5018382eadSSubhransu S. Prusty 	hda_nid_t nid;
5118382eadSSubhransu S. Prusty 	struct hdac_hdmi_cvt_params params;
5218382eadSSubhransu S. Prusty };
5318382eadSSubhransu S. Prusty 
54*b8a54545SSubhransu S. Prusty struct hdac_hdmi_eld {
55*b8a54545SSubhransu S. Prusty 	bool	monitor_present;
56*b8a54545SSubhransu S. Prusty 	bool	eld_valid;
57*b8a54545SSubhransu S. Prusty 	int	eld_size;
58*b8a54545SSubhransu S. Prusty 	char    eld_buffer[ELD_MAX_SIZE];
59*b8a54545SSubhransu S. Prusty };
60*b8a54545SSubhransu S. Prusty 
6118382eadSSubhransu S. Prusty struct hdac_hdmi_pin {
6215b91447SSubhransu S. Prusty 	struct list_head head;
6318382eadSSubhransu S. Prusty 	hda_nid_t nid;
6418382eadSSubhransu S. Prusty 	int num_mux_nids;
6518382eadSSubhransu S. Prusty 	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
66*b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_eld eld;
67*b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev;
68*b8a54545SSubhransu S. Prusty 	int repoll_count;
69*b8a54545SSubhransu S. Prusty 	struct delayed_work work;
7018382eadSSubhransu S. Prusty };
7118382eadSSubhransu S. Prusty 
7218382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map {
7318382eadSSubhransu S. Prusty 	int dai_id;
7415b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
7515b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
7618382eadSSubhransu S. Prusty };
7718382eadSSubhransu S. Prusty 
7818382eadSSubhransu S. Prusty struct hdac_hdmi_priv {
7918382eadSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map dai_map[3];
8015b91447SSubhransu S. Prusty 	struct list_head pin_list;
8115b91447SSubhransu S. Prusty 	struct list_head cvt_list;
8215b91447SSubhransu S. Prusty 	int num_pin;
8315b91447SSubhransu S. Prusty 	int num_cvt;
8418382eadSSubhransu S. Prusty };
8518382eadSSubhransu S. Prusty 
86e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
87e342ac08SSubhransu S. Prusty {
8851b2c425SGeliang Tang 	struct hdac_device *hdac = dev_to_hdac_dev(dev);
89e342ac08SSubhransu S. Prusty 
9051b2c425SGeliang Tang 	return to_ehdac_device(hdac);
91e342ac08SSubhransu S. Prusty }
92e342ac08SSubhransu S. Prusty 
93*b8a54545SSubhransu S. Prusty  /* HDMI ELD routines */
94*b8a54545SSubhransu S. Prusty static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec,
95*b8a54545SSubhransu S. Prusty 				hda_nid_t nid, int byte_index)
96*b8a54545SSubhransu S. Prusty {
97*b8a54545SSubhransu S. Prusty 	unsigned int val;
98*b8a54545SSubhransu S. Prusty 
99*b8a54545SSubhransu S. Prusty 	val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD,
100*b8a54545SSubhransu S. Prusty 							byte_index);
101*b8a54545SSubhransu S. Prusty 
102*b8a54545SSubhransu S. Prusty 	dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n",
103*b8a54545SSubhransu S. Prusty 					byte_index, val);
104*b8a54545SSubhransu S. Prusty 
105*b8a54545SSubhransu S. Prusty 	return val;
106*b8a54545SSubhransu S. Prusty }
107*b8a54545SSubhransu S. Prusty 
108*b8a54545SSubhransu S. Prusty static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid)
109*b8a54545SSubhransu S. Prusty {
110*b8a54545SSubhransu S. Prusty 	return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
111*b8a54545SSubhransu S. Prusty 						 AC_DIPSIZE_ELD_BUF);
112*b8a54545SSubhransu S. Prusty }
113*b8a54545SSubhransu S. Prusty 
114*b8a54545SSubhransu S. Prusty /*
115*b8a54545SSubhransu S. Prusty  * This function queries the ELD size and ELD data and fills in the buffer
116*b8a54545SSubhransu S. Prusty  * passed by user
117*b8a54545SSubhransu S. Prusty  */
118*b8a54545SSubhransu S. Prusty static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid,
119*b8a54545SSubhransu S. Prusty 			     unsigned char *buf, int *eld_size)
120*b8a54545SSubhransu S. Prusty {
121*b8a54545SSubhransu S. Prusty 	int i, size, ret = 0;
122*b8a54545SSubhransu S. Prusty 
123*b8a54545SSubhransu S. Prusty 	/*
124*b8a54545SSubhransu S. Prusty 	 * ELD size is initialized to zero in caller function. If no errors and
125*b8a54545SSubhransu S. Prusty 	 * ELD is valid, actual eld_size is assigned.
126*b8a54545SSubhransu S. Prusty 	 */
127*b8a54545SSubhransu S. Prusty 
128*b8a54545SSubhransu S. Prusty 	size = hdac_hdmi_get_eld_size(codec, nid);
129*b8a54545SSubhransu S. Prusty 	if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
130*b8a54545SSubhransu S. Prusty 		dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size);
131*b8a54545SSubhransu S. Prusty 		return -ERANGE;
132*b8a54545SSubhransu S. Prusty 	}
133*b8a54545SSubhransu S. Prusty 
134*b8a54545SSubhransu S. Prusty 	/* set ELD buffer */
135*b8a54545SSubhransu S. Prusty 	for (i = 0; i < size; i++) {
136*b8a54545SSubhransu S. Prusty 		unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i);
137*b8a54545SSubhransu S. Prusty 		/*
138*b8a54545SSubhransu S. Prusty 		 * Graphics driver might be writing to ELD buffer right now.
139*b8a54545SSubhransu S. Prusty 		 * Just abort. The caller will repoll after a while.
140*b8a54545SSubhransu S. Prusty 		 */
141*b8a54545SSubhransu S. Prusty 		if (!(val & AC_ELDD_ELD_VALID)) {
142*b8a54545SSubhransu S. Prusty 			dev_err(&codec->dev,
143*b8a54545SSubhransu S. Prusty 				"HDMI: invalid ELD data byte %d\n", i);
144*b8a54545SSubhransu S. Prusty 			ret = -EINVAL;
145*b8a54545SSubhransu S. Prusty 			goto error;
146*b8a54545SSubhransu S. Prusty 		}
147*b8a54545SSubhransu S. Prusty 		val &= AC_ELDD_ELD_DATA;
148*b8a54545SSubhransu S. Prusty 		/*
149*b8a54545SSubhransu S. Prusty 		 * The first byte cannot be zero. This can happen on some DVI
150*b8a54545SSubhransu S. Prusty 		 * connections. Some Intel chips may also need some 250ms delay
151*b8a54545SSubhransu S. Prusty 		 * to return non-zero ELD data, even when the graphics driver
152*b8a54545SSubhransu S. Prusty 		 * correctly writes ELD content before setting ELD_valid bit.
153*b8a54545SSubhransu S. Prusty 		 */
154*b8a54545SSubhransu S. Prusty 		if (!val && !i) {
155*b8a54545SSubhransu S. Prusty 			dev_err(&codec->dev, "HDMI: 0 ELD data\n");
156*b8a54545SSubhransu S. Prusty 			ret = -EINVAL;
157*b8a54545SSubhransu S. Prusty 			goto error;
158*b8a54545SSubhransu S. Prusty 		}
159*b8a54545SSubhransu S. Prusty 		buf[i] = val;
160*b8a54545SSubhransu S. Prusty 	}
161*b8a54545SSubhransu S. Prusty 
162*b8a54545SSubhransu S. Prusty 	*eld_size = size;
163*b8a54545SSubhransu S. Prusty error:
164*b8a54545SSubhransu S. Prusty 	return ret;
165*b8a54545SSubhransu S. Prusty }
166*b8a54545SSubhransu S. Prusty 
167b0362adbSSubhransu S. Prusty static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
168b0362adbSSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid,
169b0362adbSSubhransu S. Prusty 				u32 stream_tag, int format)
170b0362adbSSubhransu S. Prusty {
171b0362adbSSubhransu S. Prusty 	unsigned int val;
172b0362adbSSubhransu S. Prusty 
173b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
174b0362adbSSubhransu S. Prusty 			cvt_nid, pin_nid, stream_tag, format);
175b0362adbSSubhransu S. Prusty 
176b0362adbSSubhransu S. Prusty 	val = (stream_tag << 4);
177b0362adbSSubhransu S. Prusty 
178b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
179b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, val);
180b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
181b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, format);
182b0362adbSSubhransu S. Prusty 
183b0362adbSSubhransu S. Prusty 	return 0;
184b0362adbSSubhransu S. Prusty }
185b0362adbSSubhransu S. Prusty 
186a657f1d0SSubhransu S. Prusty static void
187a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
188a657f1d0SSubhransu S. Prusty 				int packet_index, int byte_index)
189a657f1d0SSubhransu S. Prusty {
190a657f1d0SSubhransu S. Prusty 	int val;
191a657f1d0SSubhransu S. Prusty 
192a657f1d0SSubhransu S. Prusty 	val = (packet_index << 5) | (byte_index & 0x1f);
193a657f1d0SSubhransu S. Prusty 
194a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
195a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_INDEX, val);
196a657f1d0SSubhransu S. Prusty }
197a657f1d0SSubhransu S. Prusty 
198a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
199a657f1d0SSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid)
200a657f1d0SSubhransu S. Prusty {
201a657f1d0SSubhransu S. Prusty 	uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
202a657f1d0SSubhransu S. Prusty 	struct hdmi_audio_infoframe frame;
203a657f1d0SSubhransu S. Prusty 	u8 *dip = (u8 *)&frame;
204a657f1d0SSubhransu S. Prusty 	int ret;
205a657f1d0SSubhransu S. Prusty 	int i;
206a657f1d0SSubhransu S. Prusty 
207a657f1d0SSubhransu S. Prusty 	hdmi_audio_infoframe_init(&frame);
208a657f1d0SSubhransu S. Prusty 
209a657f1d0SSubhransu S. Prusty 	/* Default stereo for now */
210a657f1d0SSubhransu S. Prusty 	frame.channels = 2;
211a657f1d0SSubhransu S. Prusty 
212a657f1d0SSubhransu S. Prusty 	/* setup channel count */
213a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
214a657f1d0SSubhransu S. Prusty 			    AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1);
215a657f1d0SSubhransu S. Prusty 
216a657f1d0SSubhransu S. Prusty 	ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
217a657f1d0SSubhransu S. Prusty 	if (ret < 0)
218a657f1d0SSubhransu S. Prusty 		return ret;
219a657f1d0SSubhransu S. Prusty 
220a657f1d0SSubhransu S. Prusty 	/* stop infoframe transmission */
221a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
222a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
223a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
224a657f1d0SSubhransu S. Prusty 
225a657f1d0SSubhransu S. Prusty 
226a657f1d0SSubhransu S. Prusty 	/*  Fill infoframe. Index auto-incremented */
227a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
228a657f1d0SSubhransu S. Prusty 	for (i = 0; i < sizeof(frame); i++)
229a657f1d0SSubhransu S. Prusty 		snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
230a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
231a657f1d0SSubhransu S. Prusty 
232a657f1d0SSubhransu S. Prusty 	/* Start infoframe */
233a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
234a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
235a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
236a657f1d0SSubhransu S. Prusty 
237a657f1d0SSubhransu S. Prusty 	return 0;
238a657f1d0SSubhransu S. Prusty }
239a657f1d0SSubhransu S. Prusty 
240b0362adbSSubhransu S. Prusty static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
241b0362adbSSubhransu S. Prusty 		struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
242b0362adbSSubhransu S. Prusty {
243b0362adbSSubhransu S. Prusty 	/* Power up pin widget */
24415b91447SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
24515b91447SSubhransu S. Prusty 						pwr_state))
24615b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
247b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
248b0362adbSSubhransu S. Prusty 
249b0362adbSSubhransu S. Prusty 	/* Power up converter */
25015b91447SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
25115b91447SSubhransu S. Prusty 						pwr_state))
25215b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
253b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
254b0362adbSSubhransu S. Prusty }
255b0362adbSSubhransu S. Prusty 
256b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
257b0362adbSSubhransu S. Prusty 				struct snd_soc_dai *dai)
258b0362adbSSubhransu S. Prusty {
259b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
260b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
261b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
262b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
263a657f1d0SSubhransu S. Prusty 	int ret;
264b0362adbSSubhransu S. Prusty 
265b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
266b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
267b0362adbSSubhransu S. Prusty 		return -ENODEV;
268b0362adbSSubhransu S. Prusty 	}
269b0362adbSSubhransu S. Prusty 
270b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
271b0362adbSSubhransu S. Prusty 
272b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
273b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
274b0362adbSSubhransu S. Prusty 			dd->stream_tag,	dd->format);
275b0362adbSSubhransu S. Prusty 
27615b91447SSubhransu S. Prusty 	ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
27715b91447SSubhransu S. Prusty 						dai_map->pin->nid);
278a657f1d0SSubhransu S. Prusty 	if (ret < 0)
279a657f1d0SSubhransu S. Prusty 		return ret;
280a657f1d0SSubhransu S. Prusty 
28115b91447SSubhransu S. Prusty 	return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
28215b91447SSubhransu S. Prusty 			dai_map->pin->nid, dd->stream_tag, dd->format);
283b0362adbSSubhransu S. Prusty }
284b0362adbSSubhransu S. Prusty 
285b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
286b0362adbSSubhransu S. Prusty 	struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
287b0362adbSSubhransu S. Prusty {
288b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
289b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
290b0362adbSSubhransu S. Prusty 
291b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
292b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
293b0362adbSSubhransu S. Prusty 		return -ENODEV;
294b0362adbSSubhransu S. Prusty 	}
295b0362adbSSubhransu S. Prusty 
296b0362adbSSubhransu S. Prusty 	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
2978d33ab24SSudip Mukherjee 	if (!dd)
2988d33ab24SSudip Mukherjee 		return -ENOMEM;
299b0362adbSSubhransu S. Prusty 	dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
300b0362adbSSubhransu S. Prusty 			params_channels(hparams), params_format(hparams),
301b0362adbSSubhransu S. Prusty 			24, 0);
302b0362adbSSubhransu S. Prusty 
303b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
304b0362adbSSubhransu S. Prusty 
305b0362adbSSubhransu S. Prusty 	return 0;
306b0362adbSSubhransu S. Prusty }
307b0362adbSSubhransu S. Prusty 
308b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
309b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
310b0362adbSSubhransu S. Prusty {
311b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
312b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
313b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
314b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
315b0362adbSSubhransu S. Prusty 
316b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
317b0362adbSSubhransu S. Prusty 
31815b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
319b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, 0);
32015b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
321b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, 0);
322b0362adbSSubhransu S. Prusty 
323b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
324b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, NULL);
325b0362adbSSubhransu S. Prusty 
326b0362adbSSubhransu S. Prusty 	kfree(dd);
327b0362adbSSubhransu S. Prusty 
328b0362adbSSubhransu S. Prusty 	return 0;
329b0362adbSSubhransu S. Prusty }
330b0362adbSSubhransu S. Prusty 
331b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
332b0362adbSSubhransu S. Prusty 			struct snd_soc_dai *dai)
333b0362adbSSubhransu S. Prusty {
334b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
335b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
336b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
337b0362adbSSubhransu S. Prusty 
338b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
339b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
340b0362adbSSubhransu S. Prusty 		return -ENODEV;
341b0362adbSSubhransu S. Prusty 	}
342b0362adbSSubhransu S. Prusty 
343b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
344b0362adbSSubhransu S. Prusty 
345*b8a54545SSubhransu S. Prusty 	if ((!dai_map->pin->eld.monitor_present) ||
346*b8a54545SSubhransu S. Prusty 			(!dai_map->pin->eld.eld_valid)) {
347b0362adbSSubhransu S. Prusty 
348*b8a54545SSubhransu S. Prusty 		dev_err(&hdac->hdac.dev,
349*b8a54545SSubhransu S. Prusty 				"Failed: montior present? %d ELD valid?: %d\n",
350*b8a54545SSubhransu S. Prusty 				dai_map->pin->eld.monitor_present,
351*b8a54545SSubhransu S. Prusty 				dai_map->pin->eld.eld_valid);
352*b8a54545SSubhransu S. Prusty 
353b0362adbSSubhransu S. Prusty 		return -ENODEV;
354b0362adbSSubhransu S. Prusty 	}
355b0362adbSSubhransu S. Prusty 
356b0362adbSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
357b0362adbSSubhransu S. Prusty 
35815b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
359b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
360b0362adbSSubhransu S. Prusty 
361b0362adbSSubhransu S. Prusty 	snd_pcm_hw_constraint_step(substream->runtime, 0,
362b0362adbSSubhransu S. Prusty 				   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
363b0362adbSSubhransu S. Prusty 
364b0362adbSSubhransu S. Prusty 	return 0;
365b0362adbSSubhransu S. Prusty }
366b0362adbSSubhransu S. Prusty 
367b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
368b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
369b0362adbSSubhransu S. Prusty {
370b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
371b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
372b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
373b0362adbSSubhransu S. Prusty 
374b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
375b0362adbSSubhransu S. Prusty 
376b0362adbSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
377b0362adbSSubhransu S. Prusty 
37815b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
379b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
380b0362adbSSubhransu S. Prusty }
381b0362adbSSubhransu S. Prusty 
38218382eadSSubhransu S. Prusty static int
38318382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
38418382eadSSubhransu S. Prusty {
38518382eadSSubhransu S. Prusty 	int err;
38618382eadSSubhransu S. Prusty 
38718382eadSSubhransu S. Prusty 	/* Only stereo supported as of now */
38818382eadSSubhransu S. Prusty 	cvt->params.channels_min = cvt->params.channels_max = 2;
38918382eadSSubhransu S. Prusty 
39018382eadSSubhransu S. Prusty 	err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
39118382eadSSubhransu S. Prusty 			&cvt->params.rates,
39218382eadSSubhransu S. Prusty 			&cvt->params.formats,
39318382eadSSubhransu S. Prusty 			&cvt->params.maxbps);
39418382eadSSubhransu S. Prusty 	if (err < 0)
39518382eadSSubhransu S. Prusty 		dev_err(&hdac->dev,
39618382eadSSubhransu S. Prusty 			"Failed to query pcm params for nid %d: %d\n",
39718382eadSSubhransu S. Prusty 			cvt->nid, err);
39818382eadSSubhransu S. Prusty 
39918382eadSSubhransu S. Prusty 	return err;
40018382eadSSubhransu S. Prusty }
40118382eadSSubhransu S. Prusty 
40218382eadSSubhransu S. Prusty static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
40318382eadSSubhransu S. Prusty 				enum snd_soc_dapm_type id,
40418382eadSSubhransu S. Prusty 				const char *wname, const char *stream)
40518382eadSSubhransu S. Prusty {
40618382eadSSubhransu S. Prusty 	w->id = id;
40718382eadSSubhransu S. Prusty 	w->name = wname;
40818382eadSSubhransu S. Prusty 	w->sname = stream;
40918382eadSSubhransu S. Prusty 	w->reg = SND_SOC_NOPM;
41018382eadSSubhransu S. Prusty 	w->shift = 0;
41118382eadSSubhransu S. Prusty 	w->kcontrol_news = NULL;
41218382eadSSubhransu S. Prusty 	w->num_kcontrols = 0;
41318382eadSSubhransu S. Prusty 	w->priv = NULL;
41418382eadSSubhransu S. Prusty }
41518382eadSSubhransu S. Prusty 
41618382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
41718382eadSSubhransu S. Prusty 		const char *sink, const char *control, const char *src)
41818382eadSSubhransu S. Prusty {
41918382eadSSubhransu S. Prusty 	route->sink = sink;
42018382eadSSubhransu S. Prusty 	route->source = src;
42118382eadSSubhransu S. Prusty 	route->control = control;
42218382eadSSubhransu S. Prusty 	route->connected = NULL;
42318382eadSSubhransu S. Prusty }
42418382eadSSubhransu S. Prusty 
42518382eadSSubhransu S. Prusty static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
42618382eadSSubhransu S. Prusty 					struct hdac_hdmi_dai_pin_map *dai_map)
42718382eadSSubhransu S. Prusty {
42818382eadSSubhransu S. Prusty 	struct snd_soc_dapm_route route[1];
42918382eadSSubhransu S. Prusty 	struct snd_soc_dapm_widget widgets[2] = { {0} };
43018382eadSSubhransu S. Prusty 
43118382eadSSubhransu S. Prusty 	memset(&route, 0, sizeof(route));
43218382eadSSubhransu S. Prusty 
43318382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
43418382eadSSubhransu S. Prusty 			"hif1 Output", NULL);
43518382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
43618382eadSSubhransu S. Prusty 			"Coverter 1", "hif1");
43718382eadSSubhransu S. Prusty 
43818382eadSSubhransu S. Prusty 	hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
43918382eadSSubhransu S. Prusty 
44018382eadSSubhransu S. Prusty 	snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
44118382eadSSubhransu S. Prusty 	snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
44218382eadSSubhransu S. Prusty }
44318382eadSSubhransu S. Prusty 
44415b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
44518382eadSSubhransu S. Prusty {
44615b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
44715b91447SSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
44815b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
44915b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
45018382eadSSubhransu S. Prusty 
45115b91447SSubhransu S. Prusty 	if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
45215b91447SSubhransu S. Prusty 		return -EINVAL;
45318382eadSSubhransu S. Prusty 
45415b91447SSubhransu S. Prusty 	/*
45515b91447SSubhransu S. Prusty 	 * Currently on board only 1 pin and 1 converter is enabled for
45615b91447SSubhransu S. Prusty 	 * simplification, more will be added eventually
45715b91447SSubhransu S. Prusty 	 * So using fixed map for dai_id:pin:cvt
45815b91447SSubhransu S. Prusty 	 */
45915b91447SSubhransu S. Prusty 	cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
46015b91447SSubhransu S. Prusty 	pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
46118382eadSSubhransu S. Prusty 
46215b91447SSubhransu S. Prusty 	dai_map->dai_id = 0;
46315b91447SSubhransu S. Prusty 	dai_map->pin = pin;
46415b91447SSubhransu S. Prusty 
46515b91447SSubhransu S. Prusty 	dai_map->cvt = cvt;
46618382eadSSubhransu S. Prusty 
46718382eadSSubhransu S. Prusty 	/* Enable out path for this pin widget */
46815b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
46918382eadSSubhransu S. Prusty 			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
47018382eadSSubhransu S. Prusty 
47118382eadSSubhransu S. Prusty 	/* Enable transmission */
47215b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
47318382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_1, 1);
47418382eadSSubhransu S. Prusty 
47518382eadSSubhransu S. Prusty 	/* Category Code (CC) to zero */
47615b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
47718382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_2, 0);
47818382eadSSubhransu S. Prusty 
47915b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
48018382eadSSubhransu S. Prusty 			AC_VERB_SET_CONNECT_SEL, 0);
48118382eadSSubhransu S. Prusty 
48215b91447SSubhransu S. Prusty 	return 0;
48315b91447SSubhransu S. Prusty }
48415b91447SSubhransu S. Prusty 
48515b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
48615b91447SSubhransu S. Prusty {
48715b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
48815b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
48915b91447SSubhransu S. Prusty 
49015b91447SSubhransu S. Prusty 	cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
49115b91447SSubhransu S. Prusty 	if (!cvt)
49215b91447SSubhransu S. Prusty 		return -ENOMEM;
49315b91447SSubhransu S. Prusty 
49415b91447SSubhransu S. Prusty 	cvt->nid = nid;
49515b91447SSubhransu S. Prusty 
49615b91447SSubhransu S. Prusty 	list_add_tail(&cvt->head, &hdmi->cvt_list);
49715b91447SSubhransu S. Prusty 	hdmi->num_cvt++;
49815b91447SSubhransu S. Prusty 
49915b91447SSubhransu S. Prusty 	return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
50015b91447SSubhransu S. Prusty }
50115b91447SSubhransu S. Prusty 
502*b8a54545SSubhransu S. Prusty static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
503*b8a54545SSubhransu S. Prusty {
504*b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev = pin->edev;
505*b8a54545SSubhransu S. Prusty 	int val;
506*b8a54545SSubhransu S. Prusty 
507*b8a54545SSubhransu S. Prusty 	if (!edev)
508*b8a54545SSubhransu S. Prusty 		return;
509*b8a54545SSubhransu S. Prusty 
510*b8a54545SSubhransu S. Prusty 	pin->repoll_count = repoll;
511*b8a54545SSubhransu S. Prusty 
512*b8a54545SSubhransu S. Prusty 	pm_runtime_get_sync(&edev->hdac.dev);
513*b8a54545SSubhransu S. Prusty 	val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0,
514*b8a54545SSubhransu S. Prusty 					AC_VERB_GET_PIN_SENSE, 0);
515*b8a54545SSubhransu S. Prusty 
516*b8a54545SSubhransu S. Prusty 	dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n",
517*b8a54545SSubhransu S. Prusty 						val, pin->nid);
518*b8a54545SSubhransu S. Prusty 
519*b8a54545SSubhransu S. Prusty 	pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE);
520*b8a54545SSubhransu S. Prusty 	pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV);
521*b8a54545SSubhransu S. Prusty 
522*b8a54545SSubhransu S. Prusty 	if (!pin->eld.monitor_present || !pin->eld.eld_valid) {
523*b8a54545SSubhransu S. Prusty 
524*b8a54545SSubhransu S. Prusty 		dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n",
525*b8a54545SSubhransu S. Prusty 						__func__, pin->nid);
526*b8a54545SSubhransu S. Prusty 		goto put_hdac_device;
527*b8a54545SSubhransu S. Prusty 	}
528*b8a54545SSubhransu S. Prusty 
529*b8a54545SSubhransu S. Prusty 	if (pin->eld.monitor_present && pin->eld.eld_valid) {
530*b8a54545SSubhransu S. Prusty 		/* TODO: use i915 component for reading ELD later */
531*b8a54545SSubhransu S. Prusty 		if (hdac_hdmi_get_eld(&edev->hdac, pin->nid,
532*b8a54545SSubhransu S. Prusty 				pin->eld.eld_buffer,
533*b8a54545SSubhransu S. Prusty 				&pin->eld.eld_size) == 0) {
534*b8a54545SSubhransu S. Prusty 
535*b8a54545SSubhransu S. Prusty 			print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET,
536*b8a54545SSubhransu S. Prusty 					pin->eld.eld_buffer, pin->eld.eld_size);
537*b8a54545SSubhransu S. Prusty 		} else {
538*b8a54545SSubhransu S. Prusty 			pin->eld.monitor_present = false;
539*b8a54545SSubhransu S. Prusty 			pin->eld.eld_valid = false;
540*b8a54545SSubhransu S. Prusty 		}
541*b8a54545SSubhransu S. Prusty 	}
542*b8a54545SSubhransu S. Prusty 
543*b8a54545SSubhransu S. Prusty 	/*
544*b8a54545SSubhransu S. Prusty 	 * Sometimes the pin_sense may present invalid monitor
545*b8a54545SSubhransu S. Prusty 	 * present and eld_valid. If ELD data is not valid, loop few
546*b8a54545SSubhransu S. Prusty 	 * more times to get correct pin sense and valid ELD.
547*b8a54545SSubhransu S. Prusty 	 */
548*b8a54545SSubhransu S. Prusty 	if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll)
549*b8a54545SSubhransu S. Prusty 		schedule_delayed_work(&pin->work, msecs_to_jiffies(300));
550*b8a54545SSubhransu S. Prusty 
551*b8a54545SSubhransu S. Prusty put_hdac_device:
552*b8a54545SSubhransu S. Prusty 	pm_runtime_put_sync(&edev->hdac.dev);
553*b8a54545SSubhransu S. Prusty }
554*b8a54545SSubhransu S. Prusty 
555*b8a54545SSubhransu S. Prusty static void hdac_hdmi_repoll_eld(struct work_struct *work)
556*b8a54545SSubhransu S. Prusty {
557*b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin =
558*b8a54545SSubhransu S. Prusty 		container_of(to_delayed_work(work), struct hdac_hdmi_pin, work);
559*b8a54545SSubhransu S. Prusty 
560*b8a54545SSubhransu S. Prusty 	/* picked from legacy HDA driver */
561*b8a54545SSubhransu S. Prusty 	if (pin->repoll_count++ > 6)
562*b8a54545SSubhransu S. Prusty 		pin->repoll_count = 0;
563*b8a54545SSubhransu S. Prusty 
564*b8a54545SSubhransu S. Prusty 	hdac_hdmi_present_sense(pin, pin->repoll_count);
565*b8a54545SSubhransu S. Prusty }
566*b8a54545SSubhransu S. Prusty 
56715b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
56815b91447SSubhransu S. Prusty {
56915b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
57015b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
57115b91447SSubhransu S. Prusty 
57215b91447SSubhransu S. Prusty 	pin = kzalloc(sizeof(*pin), GFP_KERNEL);
57315b91447SSubhransu S. Prusty 	if (!pin)
57415b91447SSubhransu S. Prusty 		return -ENOMEM;
57515b91447SSubhransu S. Prusty 
57615b91447SSubhransu S. Prusty 	pin->nid = nid;
57715b91447SSubhransu S. Prusty 
57815b91447SSubhransu S. Prusty 	list_add_tail(&pin->head, &hdmi->pin_list);
57915b91447SSubhransu S. Prusty 	hdmi->num_pin++;
58015b91447SSubhransu S. Prusty 
581*b8a54545SSubhransu S. Prusty 	pin->edev = edev;
582*b8a54545SSubhransu S. Prusty 	INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
583*b8a54545SSubhransu S. Prusty 
58415b91447SSubhransu S. Prusty 	return 0;
58518382eadSSubhransu S. Prusty }
58618382eadSSubhransu S. Prusty 
58718382eadSSubhransu S. Prusty /*
58818382eadSSubhransu S. Prusty  * Parse all nodes and store the cvt/pin nids in array
58918382eadSSubhransu S. Prusty  * Add one time initialization for pin and cvt widgets
59018382eadSSubhransu S. Prusty  */
59118382eadSSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
59218382eadSSubhransu S. Prusty {
59318382eadSSubhransu S. Prusty 	hda_nid_t nid;
5943c83ac23SSudip Mukherjee 	int i, num_nodes;
59518382eadSSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
59618382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
59715b91447SSubhransu S. Prusty 	int ret;
59818382eadSSubhransu S. Prusty 
5993c83ac23SSudip Mukherjee 	num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
600541140d4SSubhransu S. Prusty 	if (!nid || num_nodes <= 0) {
60118382eadSSubhransu S. Prusty 		dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
60218382eadSSubhransu S. Prusty 		return -EINVAL;
60318382eadSSubhransu S. Prusty 	}
60418382eadSSubhransu S. Prusty 
6053c83ac23SSudip Mukherjee 	hdac->num_nodes = num_nodes;
60618382eadSSubhransu S. Prusty 	hdac->start_nid = nid;
60718382eadSSubhransu S. Prusty 
60818382eadSSubhransu S. Prusty 	for (i = 0; i < hdac->num_nodes; i++, nid++) {
60918382eadSSubhransu S. Prusty 		unsigned int caps;
61018382eadSSubhransu S. Prusty 		unsigned int type;
61118382eadSSubhransu S. Prusty 
61218382eadSSubhransu S. Prusty 		caps = get_wcaps(hdac, nid);
61318382eadSSubhransu S. Prusty 		type = get_wcaps_type(caps);
61418382eadSSubhransu S. Prusty 
61518382eadSSubhransu S. Prusty 		if (!(caps & AC_WCAP_DIGITAL))
61618382eadSSubhransu S. Prusty 			continue;
61718382eadSSubhransu S. Prusty 
61818382eadSSubhransu S. Prusty 		switch (type) {
61918382eadSSubhransu S. Prusty 
62018382eadSSubhransu S. Prusty 		case AC_WID_AUD_OUT:
62115b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_cvt(edev, nid);
62215b91447SSubhransu S. Prusty 			if (ret < 0)
62315b91447SSubhransu S. Prusty 				return ret;
62418382eadSSubhransu S. Prusty 			break;
62518382eadSSubhransu S. Prusty 
62618382eadSSubhransu S. Prusty 		case AC_WID_PIN:
62715b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_pin(edev, nid);
62815b91447SSubhransu S. Prusty 			if (ret < 0)
62915b91447SSubhransu S. Prusty 				return ret;
63018382eadSSubhransu S. Prusty 			break;
63118382eadSSubhransu S. Prusty 		}
63218382eadSSubhransu S. Prusty 	}
63318382eadSSubhransu S. Prusty 
63418382eadSSubhransu S. Prusty 	hdac->end_nid = nid;
63518382eadSSubhransu S. Prusty 
63615b91447SSubhransu S. Prusty 	if (!hdmi->num_pin || !hdmi->num_cvt)
63718382eadSSubhransu S. Prusty 		return -EIO;
63818382eadSSubhransu S. Prusty 
63915b91447SSubhransu S. Prusty 	return hdac_hdmi_init_dai_map(edev);
64018382eadSSubhransu S. Prusty }
64118382eadSSubhransu S. Prusty 
642*b8a54545SSubhransu S. Prusty static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
643*b8a54545SSubhransu S. Prusty {
644*b8a54545SSubhransu S. Prusty 	struct hdac_ext_device *edev = aptr;
645*b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
646*b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
647*b8a54545SSubhransu S. Prusty 	struct snd_soc_codec *codec = edev->scodec;
648*b8a54545SSubhransu S. Prusty 
649*b8a54545SSubhransu S. Prusty 	/* Don't know how this mapping is derived */
650*b8a54545SSubhransu S. Prusty 	hda_nid_t pin_nid = port + 0x04;
651*b8a54545SSubhransu S. Prusty 
652*b8a54545SSubhransu S. Prusty 	dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid);
653*b8a54545SSubhransu S. Prusty 
654*b8a54545SSubhransu S. Prusty 	/*
655*b8a54545SSubhransu S. Prusty 	 * skip notification during system suspend (but not in runtime PM);
656*b8a54545SSubhransu S. Prusty 	 * the state will be updated at resume. Also since the ELD and
657*b8a54545SSubhransu S. Prusty 	 * connection states are updated in anyway at the end of the resume,
658*b8a54545SSubhransu S. Prusty 	 * we can skip it when received during PM process.
659*b8a54545SSubhransu S. Prusty 	 */
660*b8a54545SSubhransu S. Prusty 	if (snd_power_get_state(codec->component.card->snd_card) !=
661*b8a54545SSubhransu S. Prusty 			SNDRV_CTL_POWER_D0)
662*b8a54545SSubhransu S. Prusty 		return;
663*b8a54545SSubhransu S. Prusty 
664*b8a54545SSubhransu S. Prusty 	if (atomic_read(&edev->hdac.in_pm))
665*b8a54545SSubhransu S. Prusty 		return;
666*b8a54545SSubhransu S. Prusty 
667*b8a54545SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head) {
668*b8a54545SSubhransu S. Prusty 		if (pin->nid == pin_nid)
669*b8a54545SSubhransu S. Prusty 			hdac_hdmi_present_sense(pin, 1);
670*b8a54545SSubhransu S. Prusty 	}
671*b8a54545SSubhransu S. Prusty }
672*b8a54545SSubhransu S. Prusty 
673*b8a54545SSubhransu S. Prusty static struct i915_audio_component_audio_ops aops = {
674*b8a54545SSubhransu S. Prusty 	.pin_eld_notify	= hdac_hdmi_eld_notify_cb,
675*b8a54545SSubhransu S. Prusty };
676*b8a54545SSubhransu S. Prusty 
67718382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec)
67818382eadSSubhransu S. Prusty {
67918382eadSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
68018382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
68118382eadSSubhransu S. Prusty 	struct snd_soc_dapm_context *dapm =
68218382eadSSubhransu S. Prusty 		snd_soc_component_get_dapm(&codec->component);
683*b8a54545SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
684*b8a54545SSubhransu S. Prusty 	int ret;
68518382eadSSubhransu S. Prusty 
68618382eadSSubhransu S. Prusty 	edev->scodec = codec;
68718382eadSSubhransu S. Prusty 
68818382eadSSubhransu S. Prusty 	create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
68918382eadSSubhransu S. Prusty 
690*b8a54545SSubhransu S. Prusty 	aops.audio_ptr = edev;
691*b8a54545SSubhransu S. Prusty 	ret = snd_hdac_i915_register_notifier(&aops);
692*b8a54545SSubhransu S. Prusty 	if (ret < 0) {
693*b8a54545SSubhransu S. Prusty 		dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n",
694*b8a54545SSubhransu S. Prusty 				ret);
695*b8a54545SSubhransu S. Prusty 		return ret;
696*b8a54545SSubhransu S. Prusty 	}
697*b8a54545SSubhransu S. Prusty 
698*b8a54545SSubhransu S. Prusty 	list_for_each_entry(pin, &hdmi->pin_list, head)
699*b8a54545SSubhransu S. Prusty 		hdac_hdmi_present_sense(pin, 1);
700*b8a54545SSubhransu S. Prusty 
70118382eadSSubhransu S. Prusty 	/* Imp: Store the card pointer in hda_codec */
70218382eadSSubhransu S. Prusty 	edev->card = dapm->card->snd_card;
70318382eadSSubhransu S. Prusty 
704e342ac08SSubhransu S. Prusty 	/*
705e342ac08SSubhransu S. Prusty 	 * hdac_device core already sets the state to active and calls
706e342ac08SSubhransu S. Prusty 	 * get_noresume. So enable runtime and set the device to suspend.
707e342ac08SSubhransu S. Prusty 	 */
708e342ac08SSubhransu S. Prusty 	pm_runtime_enable(&edev->hdac.dev);
709e342ac08SSubhransu S. Prusty 	pm_runtime_put(&edev->hdac.dev);
710e342ac08SSubhransu S. Prusty 	pm_runtime_suspend(&edev->hdac.dev);
711e342ac08SSubhransu S. Prusty 
712e342ac08SSubhransu S. Prusty 	return 0;
713e342ac08SSubhransu S. Prusty }
714e342ac08SSubhransu S. Prusty 
715e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec)
716e342ac08SSubhransu S. Prusty {
717e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
718e342ac08SSubhransu S. Prusty 
719e342ac08SSubhransu S. Prusty 	pm_runtime_disable(&edev->hdac.dev);
72018382eadSSubhransu S. Prusty 	return 0;
72118382eadSSubhransu S. Prusty }
72218382eadSSubhransu S. Prusty 
72318382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = {
72418382eadSSubhransu S. Prusty 	.probe		= hdmi_codec_probe,
725e342ac08SSubhransu S. Prusty 	.remove		= hdmi_codec_remove,
72618382eadSSubhransu S. Prusty 	.idle_bias_off	= true,
72718382eadSSubhransu S. Prusty };
72818382eadSSubhransu S. Prusty 
729b0362adbSSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = {
730b0362adbSSubhransu S. Prusty 	.startup = hdac_hdmi_pcm_open,
731b0362adbSSubhransu S. Prusty 	.shutdown = hdac_hdmi_pcm_close,
732b0362adbSSubhransu S. Prusty 	.hw_params = hdac_hdmi_set_hw_params,
733b0362adbSSubhransu S. Prusty 	.prepare = hdac_hdmi_playback_prepare,
734b0362adbSSubhransu S. Prusty 	.hw_free = hdac_hdmi_playback_cleanup,
735b0362adbSSubhransu S. Prusty };
736b0362adbSSubhransu S. Prusty 
73718382eadSSubhransu S. Prusty static struct snd_soc_dai_driver hdmi_dais[] = {
73818382eadSSubhransu S. Prusty 	{	.name = "intel-hdmi-hif1",
73918382eadSSubhransu S. Prusty 		.playback = {
74018382eadSSubhransu S. Prusty 			.stream_name = "hif1",
74118382eadSSubhransu S. Prusty 			.channels_min = 2,
74218382eadSSubhransu S. Prusty 			.channels_max = 2,
74318382eadSSubhransu S. Prusty 			.rates = SNDRV_PCM_RATE_32000 |
74418382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
74518382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
74618382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
74718382eadSSubhransu S. Prusty 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
74818382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S20_3LE |
74918382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S24_LE |
75018382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S32_LE,
75118382eadSSubhransu S. Prusty 
75218382eadSSubhransu S. Prusty 		},
753b0362adbSSubhransu S. Prusty 		.ops = &hdmi_dai_ops,
75418382eadSSubhransu S. Prusty 	},
75518382eadSSubhransu S. Prusty };
75618382eadSSubhransu S. Prusty 
75718382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
75818382eadSSubhransu S. Prusty {
75918382eadSSubhransu S. Prusty 	struct hdac_device *codec = &edev->hdac;
76018382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi_priv;
76118382eadSSubhransu S. Prusty 	int ret = 0;
76218382eadSSubhransu S. Prusty 
76318382eadSSubhransu S. Prusty 	hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
76418382eadSSubhransu S. Prusty 	if (hdmi_priv == NULL)
76518382eadSSubhransu S. Prusty 		return -ENOMEM;
76618382eadSSubhransu S. Prusty 
76718382eadSSubhransu S. Prusty 	edev->private_data = hdmi_priv;
76818382eadSSubhransu S. Prusty 
76918382eadSSubhransu S. Prusty 	dev_set_drvdata(&codec->dev, edev);
77018382eadSSubhransu S. Prusty 
77115b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->pin_list);
77215b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->cvt_list);
77315b91447SSubhransu S. Prusty 
77418382eadSSubhransu S. Prusty 	ret = hdac_hdmi_parse_and_map_nid(edev);
77518382eadSSubhransu S. Prusty 	if (ret < 0)
77618382eadSSubhransu S. Prusty 		return ret;
77718382eadSSubhransu S. Prusty 
77818382eadSSubhransu S. Prusty 	/* ASoC specific initialization */
77918382eadSSubhransu S. Prusty 	return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
78018382eadSSubhransu S. Prusty 			hdmi_dais, ARRAY_SIZE(hdmi_dais));
78118382eadSSubhransu S. Prusty }
78218382eadSSubhransu S. Prusty 
78318382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
78418382eadSSubhransu S. Prusty {
78515b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
78615b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin, *pin_next;
78715b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt, *cvt_next;
78815b91447SSubhransu S. Prusty 
78918382eadSSubhransu S. Prusty 	snd_soc_unregister_codec(&edev->hdac.dev);
79018382eadSSubhransu S. Prusty 
79115b91447SSubhransu S. Prusty 	list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
79215b91447SSubhransu S. Prusty 		list_del(&cvt->head);
79315b91447SSubhransu S. Prusty 		kfree(cvt);
79415b91447SSubhransu S. Prusty 	}
79515b91447SSubhransu S. Prusty 
79615b91447SSubhransu S. Prusty 	list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
79715b91447SSubhransu S. Prusty 		list_del(&pin->head);
79815b91447SSubhransu S. Prusty 		kfree(pin);
79915b91447SSubhransu S. Prusty 	}
80015b91447SSubhransu S. Prusty 
80118382eadSSubhransu S. Prusty 	return 0;
80218382eadSSubhransu S. Prusty }
80318382eadSSubhransu S. Prusty 
804e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM
805e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev)
806e342ac08SSubhransu S. Prusty {
807e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
808e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
80907f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
81007f083abSSubhransu S. Prusty 	int err;
811e342ac08SSubhransu S. Prusty 
812e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
813e342ac08SSubhransu S. Prusty 
81407f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
81507f083abSSubhransu S. Prusty 	if (!bus)
81607f083abSSubhransu S. Prusty 		return 0;
81707f083abSSubhransu S. Prusty 
818e342ac08SSubhransu S. Prusty 	/* Power down afg */
819e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
820e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
821e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
822e342ac08SSubhransu S. Prusty 
82307f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, false);
82407f083abSSubhransu S. Prusty 	if (err < 0) {
82507f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
82607f083abSSubhransu S. Prusty 		return err;
82707f083abSSubhransu S. Prusty 	}
82807f083abSSubhransu S. Prusty 
829e342ac08SSubhransu S. Prusty 	return 0;
830e342ac08SSubhransu S. Prusty }
831e342ac08SSubhransu S. Prusty 
832e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev)
833e342ac08SSubhransu S. Prusty {
834e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
835e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
83607f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
83707f083abSSubhransu S. Prusty 	int err;
838e342ac08SSubhransu S. Prusty 
839e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
840e342ac08SSubhransu S. Prusty 
84107f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
84207f083abSSubhransu S. Prusty 	if (!bus)
84307f083abSSubhransu S. Prusty 		return 0;
84407f083abSSubhransu S. Prusty 
84507f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, true);
84607f083abSSubhransu S. Prusty 	if (err < 0) {
84707f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
84807f083abSSubhransu S. Prusty 		return err;
84907f083abSSubhransu S. Prusty 	}
85007f083abSSubhransu S. Prusty 
851e342ac08SSubhransu S. Prusty 	/* Power up afg */
852e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
853e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
854e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
855e342ac08SSubhransu S. Prusty 
856e342ac08SSubhransu S. Prusty 	return 0;
857e342ac08SSubhransu S. Prusty }
858e342ac08SSubhransu S. Prusty #else
859e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL
860e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL
861e342ac08SSubhransu S. Prusty #endif
862e342ac08SSubhransu S. Prusty 
863e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = {
864e342ac08SSubhransu S. Prusty 	SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
865e342ac08SSubhransu S. Prusty };
866e342ac08SSubhransu S. Prusty 
86718382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = {
86818382eadSSubhransu S. Prusty 	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
86918382eadSSubhransu S. Prusty 	{}
87018382eadSSubhransu S. Prusty };
87118382eadSSubhransu S. Prusty 
87218382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
87318382eadSSubhransu S. Prusty 
87418382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = {
87518382eadSSubhransu S. Prusty 	. hdac = {
87618382eadSSubhransu S. Prusty 		.driver = {
87718382eadSSubhransu S. Prusty 			.name   = "HDMI HDA Codec",
878e342ac08SSubhransu S. Prusty 			.pm = &hdac_hdmi_pm,
87918382eadSSubhransu S. Prusty 		},
88018382eadSSubhransu S. Prusty 		.id_table       = hdmi_list,
88118382eadSSubhransu S. Prusty 	},
88218382eadSSubhransu S. Prusty 	.probe          = hdac_hdmi_dev_probe,
88318382eadSSubhransu S. Prusty 	.remove         = hdac_hdmi_dev_remove,
88418382eadSSubhransu S. Prusty };
88518382eadSSubhransu S. Prusty 
88618382eadSSubhransu S. Prusty static int __init hdmi_init(void)
88718382eadSSubhransu S. Prusty {
88818382eadSSubhransu S. Prusty 	return snd_hda_ext_driver_register(&hdmi_driver);
88918382eadSSubhransu S. Prusty }
89018382eadSSubhransu S. Prusty 
89118382eadSSubhransu S. Prusty static void __exit hdmi_exit(void)
89218382eadSSubhransu S. Prusty {
89318382eadSSubhransu S. Prusty 	snd_hda_ext_driver_unregister(&hdmi_driver);
89418382eadSSubhransu S. Prusty }
89518382eadSSubhransu S. Prusty 
89618382eadSSubhransu S. Prusty module_init(hdmi_init);
89718382eadSSubhransu S. Prusty module_exit(hdmi_exit);
89818382eadSSubhransu S. Prusty 
89918382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2");
90018382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec");
90118382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
90218382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
903