xref: /openbmc/linux/sound/soc/codecs/hdac_hdmi.c (revision 15b914476bf24185534a59fb8e149d465ff79c59)
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 
3718382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params {
3818382eadSSubhransu S. Prusty 	unsigned int channels_min;
3918382eadSSubhransu S. Prusty 	unsigned int channels_max;
4018382eadSSubhransu S. Prusty 	u32 rates;
4118382eadSSubhransu S. Prusty 	u64 formats;
4218382eadSSubhransu S. Prusty 	unsigned int maxbps;
4318382eadSSubhransu S. Prusty };
4418382eadSSubhransu S. Prusty 
4518382eadSSubhransu S. Prusty struct hdac_hdmi_cvt {
46*15b91447SSubhransu S. Prusty 	struct list_head head;
4718382eadSSubhransu S. Prusty 	hda_nid_t nid;
4818382eadSSubhransu S. Prusty 	struct hdac_hdmi_cvt_params params;
4918382eadSSubhransu S. Prusty };
5018382eadSSubhransu S. Prusty 
5118382eadSSubhransu S. Prusty struct hdac_hdmi_pin {
52*15b91447SSubhransu S. Prusty 	struct list_head head;
5318382eadSSubhransu S. Prusty 	hda_nid_t nid;
5418382eadSSubhransu S. Prusty 	int num_mux_nids;
5518382eadSSubhransu S. Prusty 	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
5618382eadSSubhransu S. Prusty };
5718382eadSSubhransu S. Prusty 
5818382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map {
5918382eadSSubhransu S. Prusty 	int dai_id;
60*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
61*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
6218382eadSSubhransu S. Prusty };
6318382eadSSubhransu S. Prusty 
6418382eadSSubhransu S. Prusty struct hdac_hdmi_priv {
6518382eadSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map dai_map[3];
66*15b91447SSubhransu S. Prusty 	struct list_head pin_list;
67*15b91447SSubhransu S. Prusty 	struct list_head cvt_list;
68*15b91447SSubhransu S. Prusty 	int num_pin;
69*15b91447SSubhransu S. Prusty 	int num_cvt;
7018382eadSSubhransu S. Prusty };
7118382eadSSubhransu S. Prusty 
72e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
73e342ac08SSubhransu S. Prusty {
7451b2c425SGeliang Tang 	struct hdac_device *hdac = dev_to_hdac_dev(dev);
75e342ac08SSubhransu S. Prusty 
7651b2c425SGeliang Tang 	return to_ehdac_device(hdac);
77e342ac08SSubhransu S. Prusty }
78e342ac08SSubhransu S. Prusty 
79b0362adbSSubhransu S. Prusty static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
80b0362adbSSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid,
81b0362adbSSubhransu S. Prusty 				u32 stream_tag, int format)
82b0362adbSSubhransu S. Prusty {
83b0362adbSSubhransu S. Prusty 	unsigned int val;
84b0362adbSSubhransu S. Prusty 
85b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
86b0362adbSSubhransu S. Prusty 			cvt_nid, pin_nid, stream_tag, format);
87b0362adbSSubhransu S. Prusty 
88b0362adbSSubhransu S. Prusty 	val = (stream_tag << 4);
89b0362adbSSubhransu S. Prusty 
90b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
91b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, val);
92b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
93b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, format);
94b0362adbSSubhransu S. Prusty 
95b0362adbSSubhransu S. Prusty 	return 0;
96b0362adbSSubhransu S. Prusty }
97b0362adbSSubhransu S. Prusty 
98a657f1d0SSubhransu S. Prusty static void
99a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
100a657f1d0SSubhransu S. Prusty 				int packet_index, int byte_index)
101a657f1d0SSubhransu S. Prusty {
102a657f1d0SSubhransu S. Prusty 	int val;
103a657f1d0SSubhransu S. Prusty 
104a657f1d0SSubhransu S. Prusty 	val = (packet_index << 5) | (byte_index & 0x1f);
105a657f1d0SSubhransu S. Prusty 
106a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
107a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_INDEX, val);
108a657f1d0SSubhransu S. Prusty }
109a657f1d0SSubhransu S. Prusty 
110a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
111a657f1d0SSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid)
112a657f1d0SSubhransu S. Prusty {
113a657f1d0SSubhransu S. Prusty 	uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
114a657f1d0SSubhransu S. Prusty 	struct hdmi_audio_infoframe frame;
115a657f1d0SSubhransu S. Prusty 	u8 *dip = (u8 *)&frame;
116a657f1d0SSubhransu S. Prusty 	int ret;
117a657f1d0SSubhransu S. Prusty 	int i;
118a657f1d0SSubhransu S. Prusty 
119a657f1d0SSubhransu S. Prusty 	hdmi_audio_infoframe_init(&frame);
120a657f1d0SSubhransu S. Prusty 
121a657f1d0SSubhransu S. Prusty 	/* Default stereo for now */
122a657f1d0SSubhransu S. Prusty 	frame.channels = 2;
123a657f1d0SSubhransu S. Prusty 
124a657f1d0SSubhransu S. Prusty 	/* setup channel count */
125a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
126a657f1d0SSubhransu S. Prusty 			    AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1);
127a657f1d0SSubhransu S. Prusty 
128a657f1d0SSubhransu S. Prusty 	ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
129a657f1d0SSubhransu S. Prusty 	if (ret < 0)
130a657f1d0SSubhransu S. Prusty 		return ret;
131a657f1d0SSubhransu S. Prusty 
132a657f1d0SSubhransu S. Prusty 	/* stop infoframe transmission */
133a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
134a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
135a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
136a657f1d0SSubhransu S. Prusty 
137a657f1d0SSubhransu S. Prusty 
138a657f1d0SSubhransu S. Prusty 	/*  Fill infoframe. Index auto-incremented */
139a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
140a657f1d0SSubhransu S. Prusty 	for (i = 0; i < sizeof(frame); i++)
141a657f1d0SSubhransu S. Prusty 		snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
142a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
143a657f1d0SSubhransu S. Prusty 
144a657f1d0SSubhransu S. Prusty 	/* Start infoframe */
145a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
146a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
147a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
148a657f1d0SSubhransu S. Prusty 
149a657f1d0SSubhransu S. Prusty 	return 0;
150a657f1d0SSubhransu S. Prusty }
151a657f1d0SSubhransu S. Prusty 
152b0362adbSSubhransu S. Prusty static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
153b0362adbSSubhransu S. Prusty 		struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
154b0362adbSSubhransu S. Prusty {
155b0362adbSSubhransu S. Prusty 	/* Power up pin widget */
156*15b91447SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
157*15b91447SSubhransu S. Prusty 						pwr_state))
158*15b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
159b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
160b0362adbSSubhransu S. Prusty 
161b0362adbSSubhransu S. Prusty 	/* Power up converter */
162*15b91447SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
163*15b91447SSubhransu S. Prusty 						pwr_state))
164*15b91447SSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
165b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
166b0362adbSSubhransu S. Prusty }
167b0362adbSSubhransu S. Prusty 
168b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
169b0362adbSSubhransu S. Prusty 				struct snd_soc_dai *dai)
170b0362adbSSubhransu S. Prusty {
171b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
172b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
173b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
174b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
175a657f1d0SSubhransu S. Prusty 	int ret;
176b0362adbSSubhransu S. Prusty 
177b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
178b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
179b0362adbSSubhransu S. Prusty 		return -ENODEV;
180b0362adbSSubhransu S. Prusty 	}
181b0362adbSSubhransu S. Prusty 
182b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
183b0362adbSSubhransu S. Prusty 
184b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
185b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
186b0362adbSSubhransu S. Prusty 			dd->stream_tag,	dd->format);
187b0362adbSSubhransu S. Prusty 
188*15b91447SSubhransu S. Prusty 	ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
189*15b91447SSubhransu S. Prusty 						dai_map->pin->nid);
190a657f1d0SSubhransu S. Prusty 	if (ret < 0)
191a657f1d0SSubhransu S. Prusty 		return ret;
192a657f1d0SSubhransu S. Prusty 
193*15b91447SSubhransu S. Prusty 	return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
194*15b91447SSubhransu S. Prusty 			dai_map->pin->nid, dd->stream_tag, dd->format);
195b0362adbSSubhransu S. Prusty }
196b0362adbSSubhransu S. Prusty 
197b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
198b0362adbSSubhransu S. Prusty 	struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
199b0362adbSSubhransu S. Prusty {
200b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
201b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
202b0362adbSSubhransu S. Prusty 
203b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
204b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
205b0362adbSSubhransu S. Prusty 		return -ENODEV;
206b0362adbSSubhransu S. Prusty 	}
207b0362adbSSubhransu S. Prusty 
208b0362adbSSubhransu S. Prusty 	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
2098d33ab24SSudip Mukherjee 	if (!dd)
2108d33ab24SSudip Mukherjee 		return -ENOMEM;
211b0362adbSSubhransu S. Prusty 	dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
212b0362adbSSubhransu S. Prusty 			params_channels(hparams), params_format(hparams),
213b0362adbSSubhransu S. Prusty 			24, 0);
214b0362adbSSubhransu S. Prusty 
215b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
216b0362adbSSubhransu S. Prusty 
217b0362adbSSubhransu S. Prusty 	return 0;
218b0362adbSSubhransu S. Prusty }
219b0362adbSSubhransu S. Prusty 
220b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
221b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
222b0362adbSSubhransu S. Prusty {
223b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
224b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
225b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
226b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
227b0362adbSSubhransu S. Prusty 
228b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
229b0362adbSSubhransu S. Prusty 
230*15b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
231b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, 0);
232*15b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
233b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, 0);
234b0362adbSSubhransu S. Prusty 
235b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
236b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, NULL);
237b0362adbSSubhransu S. Prusty 
238b0362adbSSubhransu S. Prusty 	kfree(dd);
239b0362adbSSubhransu S. Prusty 
240b0362adbSSubhransu S. Prusty 	return 0;
241b0362adbSSubhransu S. Prusty }
242b0362adbSSubhransu S. Prusty 
243b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
244b0362adbSSubhransu S. Prusty 			struct snd_soc_dai *dai)
245b0362adbSSubhransu S. Prusty {
246b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
247b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
248b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
249b0362adbSSubhransu S. Prusty 	int val;
250b0362adbSSubhransu S. Prusty 
251b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
252b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
253b0362adbSSubhransu S. Prusty 		return -ENODEV;
254b0362adbSSubhransu S. Prusty 	}
255b0362adbSSubhransu S. Prusty 
256b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
257b0362adbSSubhransu S. Prusty 
258*15b91447SSubhransu S. Prusty 	val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0,
259b0362adbSSubhransu S. Prusty 					AC_VERB_GET_PIN_SENSE, 0);
260b0362adbSSubhransu S. Prusty 	dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val);
261b0362adbSSubhransu S. Prusty 
262b0362adbSSubhransu S. Prusty 	if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) {
263b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val);
264b0362adbSSubhransu S. Prusty 		return -ENODEV;
265b0362adbSSubhransu S. Prusty 	}
266b0362adbSSubhransu S. Prusty 
267b0362adbSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
268b0362adbSSubhransu S. Prusty 
269*15b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
270b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
271b0362adbSSubhransu S. Prusty 
272b0362adbSSubhransu S. Prusty 	snd_pcm_hw_constraint_step(substream->runtime, 0,
273b0362adbSSubhransu S. Prusty 				   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
274b0362adbSSubhransu S. Prusty 
275b0362adbSSubhransu S. Prusty 	return 0;
276b0362adbSSubhransu S. Prusty }
277b0362adbSSubhransu S. Prusty 
278b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
279b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
280b0362adbSSubhransu S. Prusty {
281b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
282b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
283b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
284b0362adbSSubhransu S. Prusty 
285b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
286b0362adbSSubhransu S. Prusty 
287b0362adbSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
288b0362adbSSubhransu S. Prusty 
289*15b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
290b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
291b0362adbSSubhransu S. Prusty }
292b0362adbSSubhransu S. Prusty 
29318382eadSSubhransu S. Prusty static int
29418382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
29518382eadSSubhransu S. Prusty {
29618382eadSSubhransu S. Prusty 	int err;
29718382eadSSubhransu S. Prusty 
29818382eadSSubhransu S. Prusty 	/* Only stereo supported as of now */
29918382eadSSubhransu S. Prusty 	cvt->params.channels_min = cvt->params.channels_max = 2;
30018382eadSSubhransu S. Prusty 
30118382eadSSubhransu S. Prusty 	err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
30218382eadSSubhransu S. Prusty 			&cvt->params.rates,
30318382eadSSubhransu S. Prusty 			&cvt->params.formats,
30418382eadSSubhransu S. Prusty 			&cvt->params.maxbps);
30518382eadSSubhransu S. Prusty 	if (err < 0)
30618382eadSSubhransu S. Prusty 		dev_err(&hdac->dev,
30718382eadSSubhransu S. Prusty 			"Failed to query pcm params for nid %d: %d\n",
30818382eadSSubhransu S. Prusty 			cvt->nid, err);
30918382eadSSubhransu S. Prusty 
31018382eadSSubhransu S. Prusty 	return err;
31118382eadSSubhransu S. Prusty }
31218382eadSSubhransu S. Prusty 
31318382eadSSubhransu S. Prusty static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
31418382eadSSubhransu S. Prusty 					struct hdac_hdmi_pin *pin)
31518382eadSSubhransu S. Prusty {
31618382eadSSubhransu S. Prusty 	if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
31718382eadSSubhransu S. Prusty 		dev_warn(&hdac->hdac.dev,
31818382eadSSubhransu S. Prusty 			"HDMI: pin %d wcaps %#x does not support connection list\n",
31918382eadSSubhransu S. Prusty 			pin->nid, get_wcaps(&hdac->hdac, pin->nid));
32018382eadSSubhransu S. Prusty 		return -EINVAL;
32118382eadSSubhransu S. Prusty 	}
32218382eadSSubhransu S. Prusty 
32318382eadSSubhransu S. Prusty 	pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
32418382eadSSubhransu S. Prusty 			pin->mux_nids, HDA_MAX_CONNECTIONS);
32553072460SSubhransu S. Prusty 	if (pin->num_mux_nids == 0)
32653072460SSubhransu S. Prusty 		dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n",
32753072460SSubhransu S. Prusty 								pin->nid);
32853072460SSubhransu S. Prusty 
32953072460SSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n",
33053072460SSubhransu S. Prusty 			pin->num_mux_nids, pin->nid);
33118382eadSSubhransu S. Prusty 
33218382eadSSubhransu S. Prusty 	return pin->num_mux_nids;
33318382eadSSubhransu S. Prusty }
33418382eadSSubhransu S. Prusty 
33518382eadSSubhransu S. Prusty static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
33618382eadSSubhransu S. Prusty 				enum snd_soc_dapm_type id,
33718382eadSSubhransu S. Prusty 				const char *wname, const char *stream)
33818382eadSSubhransu S. Prusty {
33918382eadSSubhransu S. Prusty 	w->id = id;
34018382eadSSubhransu S. Prusty 	w->name = wname;
34118382eadSSubhransu S. Prusty 	w->sname = stream;
34218382eadSSubhransu S. Prusty 	w->reg = SND_SOC_NOPM;
34318382eadSSubhransu S. Prusty 	w->shift = 0;
34418382eadSSubhransu S. Prusty 	w->kcontrol_news = NULL;
34518382eadSSubhransu S. Prusty 	w->num_kcontrols = 0;
34618382eadSSubhransu S. Prusty 	w->priv = NULL;
34718382eadSSubhransu S. Prusty }
34818382eadSSubhransu S. Prusty 
34918382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
35018382eadSSubhransu S. Prusty 		const char *sink, const char *control, const char *src)
35118382eadSSubhransu S. Prusty {
35218382eadSSubhransu S. Prusty 	route->sink = sink;
35318382eadSSubhransu S. Prusty 	route->source = src;
35418382eadSSubhransu S. Prusty 	route->control = control;
35518382eadSSubhransu S. Prusty 	route->connected = NULL;
35618382eadSSubhransu S. Prusty }
35718382eadSSubhransu S. Prusty 
35818382eadSSubhransu S. Prusty static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
35918382eadSSubhransu S. Prusty 					struct hdac_hdmi_dai_pin_map *dai_map)
36018382eadSSubhransu S. Prusty {
36118382eadSSubhransu S. Prusty 	struct snd_soc_dapm_route route[1];
36218382eadSSubhransu S. Prusty 	struct snd_soc_dapm_widget widgets[2] = { {0} };
36318382eadSSubhransu S. Prusty 
36418382eadSSubhransu S. Prusty 	memset(&route, 0, sizeof(route));
36518382eadSSubhransu S. Prusty 
36618382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
36718382eadSSubhransu S. Prusty 			"hif1 Output", NULL);
36818382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
36918382eadSSubhransu S. Prusty 			"Coverter 1", "hif1");
37018382eadSSubhransu S. Prusty 
37118382eadSSubhransu S. Prusty 	hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
37218382eadSSubhransu S. Prusty 
37318382eadSSubhransu S. Prusty 	snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
37418382eadSSubhransu S. Prusty 	snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
37518382eadSSubhransu S. Prusty }
37618382eadSSubhransu S. Prusty 
377*15b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
37818382eadSSubhransu S. Prusty {
379*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
380*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
381*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
382*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
38318382eadSSubhransu S. Prusty 
384*15b91447SSubhransu S. Prusty 	if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
385*15b91447SSubhransu S. Prusty 		return -EINVAL;
38618382eadSSubhransu S. Prusty 
387*15b91447SSubhransu S. Prusty 	/*
388*15b91447SSubhransu S. Prusty 	 * Currently on board only 1 pin and 1 converter is enabled for
389*15b91447SSubhransu S. Prusty 	 * simplification, more will be added eventually
390*15b91447SSubhransu S. Prusty 	 * So using fixed map for dai_id:pin:cvt
391*15b91447SSubhransu S. Prusty 	 */
392*15b91447SSubhransu S. Prusty 	cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
393*15b91447SSubhransu S. Prusty 	pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
39418382eadSSubhransu S. Prusty 
395*15b91447SSubhransu S. Prusty 	dai_map->dai_id = 0;
396*15b91447SSubhransu S. Prusty 	dai_map->pin = pin;
397*15b91447SSubhransu S. Prusty 
398*15b91447SSubhransu S. Prusty 	dai_map->cvt = cvt;
39918382eadSSubhransu S. Prusty 
40018382eadSSubhransu S. Prusty 	/* Enable out path for this pin widget */
401*15b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
40218382eadSSubhransu S. Prusty 			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
40318382eadSSubhransu S. Prusty 
40418382eadSSubhransu S. Prusty 	/* Enable transmission */
405*15b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
40618382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_1, 1);
40718382eadSSubhransu S. Prusty 
40818382eadSSubhransu S. Prusty 	/* Category Code (CC) to zero */
409*15b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
41018382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_2, 0);
41118382eadSSubhransu S. Prusty 
412*15b91447SSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
41318382eadSSubhransu S. Prusty 			AC_VERB_SET_CONNECT_SEL, 0);
41418382eadSSubhransu S. Prusty 
415*15b91447SSubhransu S. Prusty 	return 0;
416*15b91447SSubhransu S. Prusty }
417*15b91447SSubhransu S. Prusty 
418*15b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
419*15b91447SSubhransu S. Prusty {
420*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
421*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt;
422*15b91447SSubhransu S. Prusty 
423*15b91447SSubhransu S. Prusty 	cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
424*15b91447SSubhransu S. Prusty 	if (!cvt)
425*15b91447SSubhransu S. Prusty 		return -ENOMEM;
426*15b91447SSubhransu S. Prusty 
427*15b91447SSubhransu S. Prusty 	cvt->nid = nid;
428*15b91447SSubhransu S. Prusty 
429*15b91447SSubhransu S. Prusty 	list_add_tail(&cvt->head, &hdmi->cvt_list);
430*15b91447SSubhransu S. Prusty 	hdmi->num_cvt++;
431*15b91447SSubhransu S. Prusty 
432*15b91447SSubhransu S. Prusty 	return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
433*15b91447SSubhransu S. Prusty }
434*15b91447SSubhransu S. Prusty 
435*15b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
436*15b91447SSubhransu S. Prusty {
437*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
438*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin;
439*15b91447SSubhransu S. Prusty 
440*15b91447SSubhransu S. Prusty 	pin = kzalloc(sizeof(*pin), GFP_KERNEL);
441*15b91447SSubhransu S. Prusty 	if (!pin)
442*15b91447SSubhransu S. Prusty 		return -ENOMEM;
443*15b91447SSubhransu S. Prusty 
444*15b91447SSubhransu S. Prusty 	pin->nid = nid;
445*15b91447SSubhransu S. Prusty 
446*15b91447SSubhransu S. Prusty 	list_add_tail(&pin->head, &hdmi->pin_list);
447*15b91447SSubhransu S. Prusty 	hdmi->num_pin++;
448*15b91447SSubhransu S. Prusty 
449*15b91447SSubhransu S. Prusty 	return 0;
45018382eadSSubhransu S. Prusty }
45118382eadSSubhransu S. Prusty 
45218382eadSSubhransu S. Prusty /*
45318382eadSSubhransu S. Prusty  * Parse all nodes and store the cvt/pin nids in array
45418382eadSSubhransu S. Prusty  * Add one time initialization for pin and cvt widgets
45518382eadSSubhransu S. Prusty  */
45618382eadSSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
45718382eadSSubhransu S. Prusty {
45818382eadSSubhransu S. Prusty 	hda_nid_t nid;
4593c83ac23SSudip Mukherjee 	int i, num_nodes;
46018382eadSSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
46118382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
462*15b91447SSubhransu S. Prusty 	int ret;
46318382eadSSubhransu S. Prusty 
4643c83ac23SSudip Mukherjee 	num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
465541140d4SSubhransu S. Prusty 	if (!nid || num_nodes <= 0) {
46618382eadSSubhransu S. Prusty 		dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
46718382eadSSubhransu S. Prusty 		return -EINVAL;
46818382eadSSubhransu S. Prusty 	}
46918382eadSSubhransu S. Prusty 
4703c83ac23SSudip Mukherjee 	hdac->num_nodes = num_nodes;
47118382eadSSubhransu S. Prusty 	hdac->start_nid = nid;
47218382eadSSubhransu S. Prusty 
47318382eadSSubhransu S. Prusty 	for (i = 0; i < hdac->num_nodes; i++, nid++) {
47418382eadSSubhransu S. Prusty 		unsigned int caps;
47518382eadSSubhransu S. Prusty 		unsigned int type;
47618382eadSSubhransu S. Prusty 
47718382eadSSubhransu S. Prusty 		caps = get_wcaps(hdac, nid);
47818382eadSSubhransu S. Prusty 		type = get_wcaps_type(caps);
47918382eadSSubhransu S. Prusty 
48018382eadSSubhransu S. Prusty 		if (!(caps & AC_WCAP_DIGITAL))
48118382eadSSubhransu S. Prusty 			continue;
48218382eadSSubhransu S. Prusty 
48318382eadSSubhransu S. Prusty 		switch (type) {
48418382eadSSubhransu S. Prusty 
48518382eadSSubhransu S. Prusty 		case AC_WID_AUD_OUT:
486*15b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_cvt(edev, nid);
487*15b91447SSubhransu S. Prusty 			if (ret < 0)
488*15b91447SSubhransu S. Prusty 				return ret;
48918382eadSSubhransu S. Prusty 			break;
49018382eadSSubhransu S. Prusty 
49118382eadSSubhransu S. Prusty 		case AC_WID_PIN:
492*15b91447SSubhransu S. Prusty 			ret = hdac_hdmi_add_pin(edev, nid);
493*15b91447SSubhransu S. Prusty 			if (ret < 0)
494*15b91447SSubhransu S. Prusty 				return ret;
49518382eadSSubhransu S. Prusty 			break;
49618382eadSSubhransu S. Prusty 		}
49718382eadSSubhransu S. Prusty 	}
49818382eadSSubhransu S. Prusty 
49918382eadSSubhransu S. Prusty 	hdac->end_nid = nid;
50018382eadSSubhransu S. Prusty 
501*15b91447SSubhransu S. Prusty 	if (!hdmi->num_pin || !hdmi->num_cvt)
50218382eadSSubhransu S. Prusty 		return -EIO;
50318382eadSSubhransu S. Prusty 
504*15b91447SSubhransu S. Prusty 	return hdac_hdmi_init_dai_map(edev);
50518382eadSSubhransu S. Prusty }
50618382eadSSubhransu S. Prusty 
50718382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec)
50818382eadSSubhransu S. Prusty {
50918382eadSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
51018382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
51118382eadSSubhransu S. Prusty 	struct snd_soc_dapm_context *dapm =
51218382eadSSubhransu S. Prusty 		snd_soc_component_get_dapm(&codec->component);
51318382eadSSubhransu S. Prusty 
51418382eadSSubhransu S. Prusty 	edev->scodec = codec;
51518382eadSSubhransu S. Prusty 
51618382eadSSubhransu S. Prusty 	create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
51718382eadSSubhransu S. Prusty 
51818382eadSSubhransu S. Prusty 	/* Imp: Store the card pointer in hda_codec */
51918382eadSSubhransu S. Prusty 	edev->card = dapm->card->snd_card;
52018382eadSSubhransu S. Prusty 
521e342ac08SSubhransu S. Prusty 	/*
522e342ac08SSubhransu S. Prusty 	 * hdac_device core already sets the state to active and calls
523e342ac08SSubhransu S. Prusty 	 * get_noresume. So enable runtime and set the device to suspend.
524e342ac08SSubhransu S. Prusty 	 */
525e342ac08SSubhransu S. Prusty 	pm_runtime_enable(&edev->hdac.dev);
526e342ac08SSubhransu S. Prusty 	pm_runtime_put(&edev->hdac.dev);
527e342ac08SSubhransu S. Prusty 	pm_runtime_suspend(&edev->hdac.dev);
528e342ac08SSubhransu S. Prusty 
529e342ac08SSubhransu S. Prusty 	return 0;
530e342ac08SSubhransu S. Prusty }
531e342ac08SSubhransu S. Prusty 
532e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec)
533e342ac08SSubhransu S. Prusty {
534e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
535e342ac08SSubhransu S. Prusty 
536e342ac08SSubhransu S. Prusty 	pm_runtime_disable(&edev->hdac.dev);
53718382eadSSubhransu S. Prusty 	return 0;
53818382eadSSubhransu S. Prusty }
53918382eadSSubhransu S. Prusty 
54018382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = {
54118382eadSSubhransu S. Prusty 	.probe		= hdmi_codec_probe,
542e342ac08SSubhransu S. Prusty 	.remove		= hdmi_codec_remove,
54318382eadSSubhransu S. Prusty 	.idle_bias_off	= true,
54418382eadSSubhransu S. Prusty };
54518382eadSSubhransu S. Prusty 
546b0362adbSSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = {
547b0362adbSSubhransu S. Prusty 	.startup = hdac_hdmi_pcm_open,
548b0362adbSSubhransu S. Prusty 	.shutdown = hdac_hdmi_pcm_close,
549b0362adbSSubhransu S. Prusty 	.hw_params = hdac_hdmi_set_hw_params,
550b0362adbSSubhransu S. Prusty 	.prepare = hdac_hdmi_playback_prepare,
551b0362adbSSubhransu S. Prusty 	.hw_free = hdac_hdmi_playback_cleanup,
552b0362adbSSubhransu S. Prusty };
553b0362adbSSubhransu S. Prusty 
55418382eadSSubhransu S. Prusty static struct snd_soc_dai_driver hdmi_dais[] = {
55518382eadSSubhransu S. Prusty 	{	.name = "intel-hdmi-hif1",
55618382eadSSubhransu S. Prusty 		.playback = {
55718382eadSSubhransu S. Prusty 			.stream_name = "hif1",
55818382eadSSubhransu S. Prusty 			.channels_min = 2,
55918382eadSSubhransu S. Prusty 			.channels_max = 2,
56018382eadSSubhransu S. Prusty 			.rates = SNDRV_PCM_RATE_32000 |
56118382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
56218382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
56318382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
56418382eadSSubhransu S. Prusty 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
56518382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S20_3LE |
56618382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S24_LE |
56718382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S32_LE,
56818382eadSSubhransu S. Prusty 
56918382eadSSubhransu S. Prusty 		},
570b0362adbSSubhransu S. Prusty 		.ops = &hdmi_dai_ops,
57118382eadSSubhransu S. Prusty 	},
57218382eadSSubhransu S. Prusty };
57318382eadSSubhransu S. Prusty 
57418382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
57518382eadSSubhransu S. Prusty {
57618382eadSSubhransu S. Prusty 	struct hdac_device *codec = &edev->hdac;
57718382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi_priv;
57818382eadSSubhransu S. Prusty 	int ret = 0;
57918382eadSSubhransu S. Prusty 
58018382eadSSubhransu S. Prusty 	hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
58118382eadSSubhransu S. Prusty 	if (hdmi_priv == NULL)
58218382eadSSubhransu S. Prusty 		return -ENOMEM;
58318382eadSSubhransu S. Prusty 
58418382eadSSubhransu S. Prusty 	edev->private_data = hdmi_priv;
58518382eadSSubhransu S. Prusty 
58618382eadSSubhransu S. Prusty 	dev_set_drvdata(&codec->dev, edev);
58718382eadSSubhransu S. Prusty 
588*15b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->pin_list);
589*15b91447SSubhransu S. Prusty 	INIT_LIST_HEAD(&hdmi_priv->cvt_list);
590*15b91447SSubhransu S. Prusty 
59118382eadSSubhransu S. Prusty 	ret = hdac_hdmi_parse_and_map_nid(edev);
59218382eadSSubhransu S. Prusty 	if (ret < 0)
59318382eadSSubhransu S. Prusty 		return ret;
59418382eadSSubhransu S. Prusty 
59518382eadSSubhransu S. Prusty 	/* ASoC specific initialization */
59618382eadSSubhransu S. Prusty 	return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
59718382eadSSubhransu S. Prusty 			hdmi_dais, ARRAY_SIZE(hdmi_dais));
59818382eadSSubhransu S. Prusty }
59918382eadSSubhransu S. Prusty 
60018382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
60118382eadSSubhransu S. Prusty {
602*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
603*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_pin *pin, *pin_next;
604*15b91447SSubhransu S. Prusty 	struct hdac_hdmi_cvt *cvt, *cvt_next;
605*15b91447SSubhransu S. Prusty 
60618382eadSSubhransu S. Prusty 	snd_soc_unregister_codec(&edev->hdac.dev);
60718382eadSSubhransu S. Prusty 
608*15b91447SSubhransu S. Prusty 	list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
609*15b91447SSubhransu S. Prusty 		list_del(&cvt->head);
610*15b91447SSubhransu S. Prusty 		kfree(cvt);
611*15b91447SSubhransu S. Prusty 	}
612*15b91447SSubhransu S. Prusty 
613*15b91447SSubhransu S. Prusty 	list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
614*15b91447SSubhransu S. Prusty 		list_del(&pin->head);
615*15b91447SSubhransu S. Prusty 		kfree(pin);
616*15b91447SSubhransu S. Prusty 	}
617*15b91447SSubhransu S. Prusty 
61818382eadSSubhransu S. Prusty 	return 0;
61918382eadSSubhransu S. Prusty }
62018382eadSSubhransu S. Prusty 
621e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM
622e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev)
623e342ac08SSubhransu S. Prusty {
624e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
625e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
62607f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
62707f083abSSubhransu S. Prusty 	int err;
628e342ac08SSubhransu S. Prusty 
629e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
630e342ac08SSubhransu S. Prusty 
63107f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
63207f083abSSubhransu S. Prusty 	if (!bus)
63307f083abSSubhransu S. Prusty 		return 0;
63407f083abSSubhransu S. Prusty 
635e342ac08SSubhransu S. Prusty 	/* Power down afg */
636e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
637e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
638e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
639e342ac08SSubhransu S. Prusty 
64007f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, false);
64107f083abSSubhransu S. Prusty 	if (err < 0) {
64207f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
64307f083abSSubhransu S. Prusty 		return err;
64407f083abSSubhransu S. Prusty 	}
64507f083abSSubhransu S. Prusty 
646e342ac08SSubhransu S. Prusty 	return 0;
647e342ac08SSubhransu S. Prusty }
648e342ac08SSubhransu S. Prusty 
649e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev)
650e342ac08SSubhransu S. Prusty {
651e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
652e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
65307f083abSSubhransu S. Prusty 	struct hdac_bus *bus = hdac->bus;
65407f083abSSubhransu S. Prusty 	int err;
655e342ac08SSubhransu S. Prusty 
656e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
657e342ac08SSubhransu S. Prusty 
65807f083abSSubhransu S. Prusty 	/* controller may not have been initialized for the first time */
65907f083abSSubhransu S. Prusty 	if (!bus)
66007f083abSSubhransu S. Prusty 		return 0;
66107f083abSSubhransu S. Prusty 
66207f083abSSubhransu S. Prusty 	err = snd_hdac_display_power(bus, true);
66307f083abSSubhransu S. Prusty 	if (err < 0) {
66407f083abSSubhransu S. Prusty 		dev_err(bus->dev, "Cannot turn on display power on i915\n");
66507f083abSSubhransu S. Prusty 		return err;
66607f083abSSubhransu S. Prusty 	}
66707f083abSSubhransu S. Prusty 
668e342ac08SSubhransu S. Prusty 	/* Power up afg */
669e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
670e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
671e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
672e342ac08SSubhransu S. Prusty 
673e342ac08SSubhransu S. Prusty 	return 0;
674e342ac08SSubhransu S. Prusty }
675e342ac08SSubhransu S. Prusty #else
676e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL
677e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL
678e342ac08SSubhransu S. Prusty #endif
679e342ac08SSubhransu S. Prusty 
680e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = {
681e342ac08SSubhransu S. Prusty 	SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
682e342ac08SSubhransu S. Prusty };
683e342ac08SSubhransu S. Prusty 
68418382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = {
68518382eadSSubhransu S. Prusty 	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
68618382eadSSubhransu S. Prusty 	{}
68718382eadSSubhransu S. Prusty };
68818382eadSSubhransu S. Prusty 
68918382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
69018382eadSSubhransu S. Prusty 
69118382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = {
69218382eadSSubhransu S. Prusty 	. hdac = {
69318382eadSSubhransu S. Prusty 		.driver = {
69418382eadSSubhransu S. Prusty 			.name   = "HDMI HDA Codec",
695e342ac08SSubhransu S. Prusty 			.pm = &hdac_hdmi_pm,
69618382eadSSubhransu S. Prusty 		},
69718382eadSSubhransu S. Prusty 		.id_table       = hdmi_list,
69818382eadSSubhransu S. Prusty 	},
69918382eadSSubhransu S. Prusty 	.probe          = hdac_hdmi_dev_probe,
70018382eadSSubhransu S. Prusty 	.remove         = hdac_hdmi_dev_remove,
70118382eadSSubhransu S. Prusty };
70218382eadSSubhransu S. Prusty 
70318382eadSSubhransu S. Prusty static int __init hdmi_init(void)
70418382eadSSubhransu S. Prusty {
70518382eadSSubhransu S. Prusty 	return snd_hda_ext_driver_register(&hdmi_driver);
70618382eadSSubhransu S. Prusty }
70718382eadSSubhransu S. Prusty 
70818382eadSSubhransu S. Prusty static void __exit hdmi_exit(void)
70918382eadSSubhransu S. Prusty {
71018382eadSSubhransu S. Prusty 	snd_hda_ext_driver_unregister(&hdmi_driver);
71118382eadSSubhransu S. Prusty }
71218382eadSSubhransu S. Prusty 
71318382eadSSubhransu S. Prusty module_init(hdmi_init);
71418382eadSSubhransu S. Prusty module_exit(hdmi_exit);
71518382eadSSubhransu S. Prusty 
71618382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2");
71718382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec");
71818382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
71918382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
720