xref: /openbmc/linux/sound/soc/codecs/hdac_hdmi.c (revision a657f1d05fd3eadb61f771e659f5d42940003d93)
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>
24*a657f1d0SSubhransu 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>
2818382eadSSubhransu S. Prusty #include "../../hda/local.h"
2918382eadSSubhransu S. Prusty 
30b0362adbSSubhransu S. Prusty #define AMP_OUT_MUTE		0xb080
31b0362adbSSubhransu S. Prusty #define AMP_OUT_UNMUTE		0xb000
3218382eadSSubhransu S. Prusty #define PIN_OUT			(AC_PINCTL_OUT_EN)
33b0362adbSSubhransu S. Prusty 
3418382eadSSubhransu S. Prusty #define HDA_MAX_CONNECTIONS     32
3518382eadSSubhransu S. Prusty 
3618382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params {
3718382eadSSubhransu S. Prusty 	unsigned int channels_min;
3818382eadSSubhransu S. Prusty 	unsigned int channels_max;
3918382eadSSubhransu S. Prusty 	u32 rates;
4018382eadSSubhransu S. Prusty 	u64 formats;
4118382eadSSubhransu S. Prusty 	unsigned int maxbps;
4218382eadSSubhransu S. Prusty };
4318382eadSSubhransu S. Prusty 
4418382eadSSubhransu S. Prusty struct hdac_hdmi_cvt {
4518382eadSSubhransu S. Prusty 	hda_nid_t nid;
4618382eadSSubhransu S. Prusty 	struct hdac_hdmi_cvt_params params;
4718382eadSSubhransu S. Prusty };
4818382eadSSubhransu S. Prusty 
4918382eadSSubhransu S. Prusty struct hdac_hdmi_pin {
5018382eadSSubhransu S. Prusty 	hda_nid_t nid;
5118382eadSSubhransu S. Prusty 	int num_mux_nids;
5218382eadSSubhransu S. Prusty 	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
5318382eadSSubhransu S. Prusty };
5418382eadSSubhransu S. Prusty 
5518382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map {
5618382eadSSubhransu S. Prusty 	int dai_id;
5718382eadSSubhransu S. Prusty 	struct hdac_hdmi_pin pin;
5818382eadSSubhransu S. Prusty 	struct hdac_hdmi_cvt cvt;
5918382eadSSubhransu S. Prusty };
6018382eadSSubhransu S. Prusty 
6118382eadSSubhransu S. Prusty struct hdac_hdmi_priv {
6218382eadSSubhransu S. Prusty 	hda_nid_t pin_nid[3];
6318382eadSSubhransu S. Prusty 	hda_nid_t cvt_nid[3];
6418382eadSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map dai_map[3];
6518382eadSSubhransu S. Prusty };
6618382eadSSubhransu S. Prusty 
67e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
68e342ac08SSubhransu S. Prusty {
69e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = container_of(dev, struct hdac_device, dev);
70e342ac08SSubhransu S. Prusty 
71e342ac08SSubhransu S. Prusty 	return container_of(hdac, struct hdac_ext_device, hdac);
72e342ac08SSubhransu S. Prusty }
73e342ac08SSubhransu S. Prusty 
74b0362adbSSubhransu S. Prusty static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
75b0362adbSSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid,
76b0362adbSSubhransu S. Prusty 				u32 stream_tag, int format)
77b0362adbSSubhransu S. Prusty {
78b0362adbSSubhransu S. Prusty 	unsigned int val;
79b0362adbSSubhransu S. Prusty 
80b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
81b0362adbSSubhransu S. Prusty 			cvt_nid, pin_nid, stream_tag, format);
82b0362adbSSubhransu S. Prusty 
83b0362adbSSubhransu S. Prusty 	val = (stream_tag << 4);
84b0362adbSSubhransu S. Prusty 
85b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
86b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, val);
87b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
88b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, format);
89b0362adbSSubhransu S. Prusty 
90b0362adbSSubhransu S. Prusty 	return 0;
91b0362adbSSubhransu S. Prusty }
92b0362adbSSubhransu S. Prusty 
93*a657f1d0SSubhransu S. Prusty static void
94*a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
95*a657f1d0SSubhransu S. Prusty 				int packet_index, int byte_index)
96*a657f1d0SSubhransu S. Prusty {
97*a657f1d0SSubhransu S. Prusty 	int val;
98*a657f1d0SSubhransu S. Prusty 
99*a657f1d0SSubhransu S. Prusty 	val = (packet_index << 5) | (byte_index & 0x1f);
100*a657f1d0SSubhransu S. Prusty 
101*a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
102*a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_INDEX, val);
103*a657f1d0SSubhransu S. Prusty }
104*a657f1d0SSubhransu S. Prusty 
105*a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
106*a657f1d0SSubhransu S. Prusty 				hda_nid_t cvt_nid, hda_nid_t pin_nid)
107*a657f1d0SSubhransu S. Prusty {
108*a657f1d0SSubhransu S. Prusty 	uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
109*a657f1d0SSubhransu S. Prusty 	struct hdmi_audio_infoframe frame;
110*a657f1d0SSubhransu S. Prusty 	u8 *dip = (u8 *)&frame;
111*a657f1d0SSubhransu S. Prusty 	int ret;
112*a657f1d0SSubhransu S. Prusty 	int i;
113*a657f1d0SSubhransu S. Prusty 
114*a657f1d0SSubhransu S. Prusty 	hdmi_audio_infoframe_init(&frame);
115*a657f1d0SSubhransu S. Prusty 
116*a657f1d0SSubhransu S. Prusty 	/* Default stereo for now */
117*a657f1d0SSubhransu S. Prusty 	frame.channels = 2;
118*a657f1d0SSubhransu S. Prusty 
119*a657f1d0SSubhransu S. Prusty 	/* setup channel count */
120*a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
121*a657f1d0SSubhransu S. Prusty 			    AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1);
122*a657f1d0SSubhransu S. Prusty 
123*a657f1d0SSubhransu S. Prusty 	ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
124*a657f1d0SSubhransu S. Prusty 	if (ret < 0)
125*a657f1d0SSubhransu S. Prusty 		return ret;
126*a657f1d0SSubhransu S. Prusty 
127*a657f1d0SSubhransu S. Prusty 	/* stop infoframe transmission */
128*a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
129*a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
130*a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
131*a657f1d0SSubhransu S. Prusty 
132*a657f1d0SSubhransu S. Prusty 
133*a657f1d0SSubhransu S. Prusty 	/*  Fill infoframe. Index auto-incremented */
134*a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
135*a657f1d0SSubhransu S. Prusty 	for (i = 0; i < sizeof(frame); i++)
136*a657f1d0SSubhransu S. Prusty 		snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
137*a657f1d0SSubhransu S. Prusty 				AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
138*a657f1d0SSubhransu S. Prusty 
139*a657f1d0SSubhransu S. Prusty 	/* Start infoframe */
140*a657f1d0SSubhransu S. Prusty 	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
141*a657f1d0SSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
142*a657f1d0SSubhransu S. Prusty 			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
143*a657f1d0SSubhransu S. Prusty 
144*a657f1d0SSubhransu S. Prusty 	return 0;
145*a657f1d0SSubhransu S. Prusty }
146*a657f1d0SSubhransu S. Prusty 
147b0362adbSSubhransu S. Prusty static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
148b0362adbSSubhransu S. Prusty 		struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
149b0362adbSSubhransu S. Prusty {
150b0362adbSSubhransu S. Prusty 	/* Power up pin widget */
151b0362adbSSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin.nid, pwr_state))
152b0362adbSSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->pin.nid, 0,
153b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
154b0362adbSSubhransu S. Prusty 
155b0362adbSSubhransu S. Prusty 	/* Power up converter */
156b0362adbSSubhransu S. Prusty 	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt.nid, pwr_state))
157b0362adbSSubhransu S. Prusty 		snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0,
158b0362adbSSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, pwr_state);
159b0362adbSSubhransu S. Prusty }
160b0362adbSSubhransu S. Prusty 
161b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
162b0362adbSSubhransu S. Prusty 				struct snd_soc_dai *dai)
163b0362adbSSubhransu S. Prusty {
164b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
165b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
166b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
167b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
168*a657f1d0SSubhransu S. Prusty 	int ret;
169b0362adbSSubhransu S. Prusty 
170b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
171b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
172b0362adbSSubhransu S. Prusty 		return -ENODEV;
173b0362adbSSubhransu S. Prusty 	}
174b0362adbSSubhransu S. Prusty 
175b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
176b0362adbSSubhransu S. Prusty 
177b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
178b0362adbSSubhransu S. Prusty 	dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
179b0362adbSSubhransu S. Prusty 			dd->stream_tag,	dd->format);
180b0362adbSSubhransu S. Prusty 
181*a657f1d0SSubhransu S. Prusty 	ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt.nid,
182*a657f1d0SSubhransu S. Prusty 						dai_map->pin.nid);
183*a657f1d0SSubhransu S. Prusty 	if (ret < 0)
184*a657f1d0SSubhransu S. Prusty 		return ret;
185*a657f1d0SSubhransu S. Prusty 
186b0362adbSSubhransu S. Prusty 	return hdac_hdmi_setup_stream(hdac, dai_map->cvt.nid, dai_map->pin.nid,
187b0362adbSSubhransu S. Prusty 					dd->stream_tag, dd->format);
188b0362adbSSubhransu S. Prusty }
189b0362adbSSubhransu S. Prusty 
190b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
191b0362adbSSubhransu S. Prusty 	struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
192b0362adbSSubhransu S. Prusty {
193b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
194b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
195b0362adbSSubhransu S. Prusty 
196b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
197b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
198b0362adbSSubhransu S. Prusty 		return -ENODEV;
199b0362adbSSubhransu S. Prusty 	}
200b0362adbSSubhransu S. Prusty 
201b0362adbSSubhransu S. Prusty 	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
202b0362adbSSubhransu S. Prusty 	dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
203b0362adbSSubhransu S. Prusty 			params_channels(hparams), params_format(hparams),
204b0362adbSSubhransu S. Prusty 			24, 0);
205b0362adbSSubhransu S. Prusty 
206b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
207b0362adbSSubhransu S. Prusty 
208b0362adbSSubhransu S. Prusty 	return 0;
209b0362adbSSubhransu S. Prusty }
210b0362adbSSubhransu S. Prusty 
211b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
212b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
213b0362adbSSubhransu S. Prusty {
214b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
215b0362adbSSubhransu S. Prusty 	struct hdac_ext_dma_params *dd;
216b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
217b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
218b0362adbSSubhransu S. Prusty 
219b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
220b0362adbSSubhransu S. Prusty 
221b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0,
222b0362adbSSubhransu S. Prusty 				AC_VERB_SET_CHANNEL_STREAMID, 0);
223b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0,
224b0362adbSSubhransu S. Prusty 				AC_VERB_SET_STREAM_FORMAT, 0);
225b0362adbSSubhransu S. Prusty 
226b0362adbSSubhransu S. Prusty 	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
227b0362adbSSubhransu S. Prusty 	snd_soc_dai_set_dma_data(dai, substream, NULL);
228b0362adbSSubhransu S. Prusty 
229b0362adbSSubhransu S. Prusty 	kfree(dd);
230b0362adbSSubhransu S. Prusty 
231b0362adbSSubhransu S. Prusty 	return 0;
232b0362adbSSubhransu S. Prusty }
233b0362adbSSubhransu S. Prusty 
234b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
235b0362adbSSubhransu S. Prusty 			struct snd_soc_dai *dai)
236b0362adbSSubhransu S. Prusty {
237b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
238b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
239b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
240b0362adbSSubhransu S. Prusty 	int val;
241b0362adbSSubhransu S. Prusty 
242b0362adbSSubhransu S. Prusty 	if (dai->id > 0) {
243b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
244b0362adbSSubhransu S. Prusty 		return -ENODEV;
245b0362adbSSubhransu S. Prusty 	}
246b0362adbSSubhransu S. Prusty 
247b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
248b0362adbSSubhransu S. Prusty 
249b0362adbSSubhransu S. Prusty 	val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin.nid, 0,
250b0362adbSSubhransu S. Prusty 					AC_VERB_GET_PIN_SENSE, 0);
251b0362adbSSubhransu S. Prusty 	dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val);
252b0362adbSSubhransu S. Prusty 
253b0362adbSSubhransu S. Prusty 	if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) {
254b0362adbSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val);
255b0362adbSSubhransu S. Prusty 		return -ENODEV;
256b0362adbSSubhransu S. Prusty 	}
257b0362adbSSubhransu S. Prusty 
258b0362adbSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
259b0362adbSSubhransu S. Prusty 
260b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0,
261b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
262b0362adbSSubhransu S. Prusty 
263b0362adbSSubhransu S. Prusty 	snd_pcm_hw_constraint_step(substream->runtime, 0,
264b0362adbSSubhransu S. Prusty 				   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
265b0362adbSSubhransu S. Prusty 
266b0362adbSSubhransu S. Prusty 	return 0;
267b0362adbSSubhransu S. Prusty }
268b0362adbSSubhransu S. Prusty 
269b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
270b0362adbSSubhransu S. Prusty 		struct snd_soc_dai *dai)
271b0362adbSSubhransu S. Prusty {
272b0362adbSSubhransu S. Prusty 	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
273b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = hdac->private_data;
274b0362adbSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map *dai_map;
275b0362adbSSubhransu S. Prusty 
276b0362adbSSubhransu S. Prusty 	dai_map = &hdmi->dai_map[dai->id];
277b0362adbSSubhransu S. Prusty 
278b0362adbSSubhransu S. Prusty 	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
279b0362adbSSubhransu S. Prusty 
280b0362adbSSubhransu S. Prusty 	snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0,
281b0362adbSSubhransu S. Prusty 			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
282b0362adbSSubhransu S. Prusty }
283b0362adbSSubhransu S. Prusty 
28418382eadSSubhransu S. Prusty static int
28518382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
28618382eadSSubhransu S. Prusty {
28718382eadSSubhransu S. Prusty 	int err;
28818382eadSSubhransu S. Prusty 
28918382eadSSubhransu S. Prusty 	/* Only stereo supported as of now */
29018382eadSSubhransu S. Prusty 	cvt->params.channels_min = cvt->params.channels_max = 2;
29118382eadSSubhransu S. Prusty 
29218382eadSSubhransu S. Prusty 	err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
29318382eadSSubhransu S. Prusty 			&cvt->params.rates,
29418382eadSSubhransu S. Prusty 			&cvt->params.formats,
29518382eadSSubhransu S. Prusty 			&cvt->params.maxbps);
29618382eadSSubhransu S. Prusty 	if (err < 0)
29718382eadSSubhransu S. Prusty 		dev_err(&hdac->dev,
29818382eadSSubhransu S. Prusty 			"Failed to query pcm params for nid %d: %d\n",
29918382eadSSubhransu S. Prusty 			cvt->nid, err);
30018382eadSSubhransu S. Prusty 
30118382eadSSubhransu S. Prusty 	return err;
30218382eadSSubhransu S. Prusty }
30318382eadSSubhransu S. Prusty 
30418382eadSSubhransu S. Prusty static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
30518382eadSSubhransu S. Prusty 					struct hdac_hdmi_pin *pin)
30618382eadSSubhransu S. Prusty {
30718382eadSSubhransu S. Prusty 	if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
30818382eadSSubhransu S. Prusty 		dev_warn(&hdac->hdac.dev,
30918382eadSSubhransu S. Prusty 			"HDMI: pin %d wcaps %#x does not support connection list\n",
31018382eadSSubhransu S. Prusty 			pin->nid, get_wcaps(&hdac->hdac, pin->nid));
31118382eadSSubhransu S. Prusty 		return -EINVAL;
31218382eadSSubhransu S. Prusty 	}
31318382eadSSubhransu S. Prusty 
31418382eadSSubhransu S. Prusty 	pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
31518382eadSSubhransu S. Prusty 			pin->mux_nids, HDA_MAX_CONNECTIONS);
31618382eadSSubhransu S. Prusty 	if (pin->num_mux_nids == 0) {
31718382eadSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "No connections found\n");
31818382eadSSubhransu S. Prusty 		return -ENODEV;
31918382eadSSubhransu S. Prusty 	}
32018382eadSSubhransu S. Prusty 
32118382eadSSubhransu S. Prusty 	return pin->num_mux_nids;
32218382eadSSubhransu S. Prusty }
32318382eadSSubhransu S. Prusty 
32418382eadSSubhransu S. Prusty static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
32518382eadSSubhransu S. Prusty 				enum snd_soc_dapm_type id,
32618382eadSSubhransu S. Prusty 				const char *wname, const char *stream)
32718382eadSSubhransu S. Prusty {
32818382eadSSubhransu S. Prusty 	w->id = id;
32918382eadSSubhransu S. Prusty 	w->name = wname;
33018382eadSSubhransu S. Prusty 	w->sname = stream;
33118382eadSSubhransu S. Prusty 	w->reg = SND_SOC_NOPM;
33218382eadSSubhransu S. Prusty 	w->shift = 0;
33318382eadSSubhransu S. Prusty 	w->kcontrol_news = NULL;
33418382eadSSubhransu S. Prusty 	w->num_kcontrols = 0;
33518382eadSSubhransu S. Prusty 	w->priv = NULL;
33618382eadSSubhransu S. Prusty }
33718382eadSSubhransu S. Prusty 
33818382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
33918382eadSSubhransu S. Prusty 		const char *sink, const char *control, const char *src)
34018382eadSSubhransu S. Prusty {
34118382eadSSubhransu S. Prusty 	route->sink = sink;
34218382eadSSubhransu S. Prusty 	route->source = src;
34318382eadSSubhransu S. Prusty 	route->control = control;
34418382eadSSubhransu S. Prusty 	route->connected = NULL;
34518382eadSSubhransu S. Prusty }
34618382eadSSubhransu S. Prusty 
34718382eadSSubhransu S. Prusty static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
34818382eadSSubhransu S. Prusty 					struct hdac_hdmi_dai_pin_map *dai_map)
34918382eadSSubhransu S. Prusty {
35018382eadSSubhransu S. Prusty 	struct snd_soc_dapm_route route[1];
35118382eadSSubhransu S. Prusty 	struct snd_soc_dapm_widget widgets[2] = { {0} };
35218382eadSSubhransu S. Prusty 
35318382eadSSubhransu S. Prusty 	memset(&route, 0, sizeof(route));
35418382eadSSubhransu S. Prusty 
35518382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
35618382eadSSubhransu S. Prusty 			"hif1 Output", NULL);
35718382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
35818382eadSSubhransu S. Prusty 			"Coverter 1", "hif1");
35918382eadSSubhransu S. Prusty 
36018382eadSSubhransu S. Prusty 	hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
36118382eadSSubhransu S. Prusty 
36218382eadSSubhransu S. Prusty 	snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
36318382eadSSubhransu S. Prusty 	snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
36418382eadSSubhransu S. Prusty }
36518382eadSSubhransu S. Prusty 
36618382eadSSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev,
36718382eadSSubhransu S. Prusty 			struct hdac_hdmi_dai_pin_map *dai_map,
36818382eadSSubhransu S. Prusty 			hda_nid_t pin_nid, hda_nid_t cvt_nid, int dai_id)
36918382eadSSubhransu S. Prusty {
37018382eadSSubhransu S. Prusty 	int ret;
37118382eadSSubhransu S. Prusty 
37218382eadSSubhransu S. Prusty 	dai_map->dai_id = dai_id;
37318382eadSSubhransu S. Prusty 	dai_map->pin.nid = pin_nid;
37418382eadSSubhransu S. Prusty 
37518382eadSSubhransu S. Prusty 	ret = hdac_hdmi_query_pin_connlist(edev, &dai_map->pin);
37618382eadSSubhransu S. Prusty 	if (ret < 0) {
37718382eadSSubhransu S. Prusty 		dev_err(&edev->hdac.dev,
37818382eadSSubhransu S. Prusty 			"Error querying connection list: %d\n", ret);
37918382eadSSubhransu S. Prusty 		return ret;
38018382eadSSubhransu S. Prusty 	}
38118382eadSSubhransu S. Prusty 
38218382eadSSubhransu S. Prusty 	dai_map->cvt.nid = cvt_nid;
38318382eadSSubhransu S. Prusty 
38418382eadSSubhransu S. Prusty 	/* Enable out path for this pin widget */
38518382eadSSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin_nid, 0,
38618382eadSSubhransu S. Prusty 			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
38718382eadSSubhransu S. Prusty 
38818382eadSSubhransu S. Prusty 	/* Enable transmission */
38918382eadSSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt_nid, 0,
39018382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_1, 1);
39118382eadSSubhransu S. Prusty 
39218382eadSSubhransu S. Prusty 	/* Category Code (CC) to zero */
39318382eadSSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt_nid, 0,
39418382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_2, 0);
39518382eadSSubhransu S. Prusty 
39618382eadSSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin_nid, 0,
39718382eadSSubhransu S. Prusty 			AC_VERB_SET_CONNECT_SEL, 0);
39818382eadSSubhransu S. Prusty 
39918382eadSSubhransu S. Prusty 	return hdac_hdmi_query_cvt_params(&edev->hdac, &dai_map->cvt);
40018382eadSSubhransu S. Prusty }
40118382eadSSubhransu S. Prusty 
40218382eadSSubhransu S. Prusty /*
40318382eadSSubhransu S. Prusty  * Parse all nodes and store the cvt/pin nids in array
40418382eadSSubhransu S. Prusty  * Add one time initialization for pin and cvt widgets
40518382eadSSubhransu S. Prusty  */
40618382eadSSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
40718382eadSSubhransu S. Prusty {
40818382eadSSubhransu S. Prusty 	hda_nid_t nid;
40918382eadSSubhransu S. Prusty 	int i;
41018382eadSSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
41118382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
41218382eadSSubhransu S. Prusty 	int cvt_nid = 0, pin_nid = 0;
41318382eadSSubhransu S. Prusty 
41418382eadSSubhransu S. Prusty 	hdac->num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
41518382eadSSubhransu S. Prusty 	if (!nid || hdac->num_nodes < 0) {
41618382eadSSubhransu S. Prusty 		dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
41718382eadSSubhransu S. Prusty 		return -EINVAL;
41818382eadSSubhransu S. Prusty 	}
41918382eadSSubhransu S. Prusty 
42018382eadSSubhransu S. Prusty 	hdac->start_nid = nid;
42118382eadSSubhransu S. Prusty 
42218382eadSSubhransu S. Prusty 	for (i = 0; i < hdac->num_nodes; i++, nid++) {
42318382eadSSubhransu S. Prusty 		unsigned int caps;
42418382eadSSubhransu S. Prusty 		unsigned int type;
42518382eadSSubhransu S. Prusty 
42618382eadSSubhransu S. Prusty 		caps = get_wcaps(hdac, nid);
42718382eadSSubhransu S. Prusty 		type = get_wcaps_type(caps);
42818382eadSSubhransu S. Prusty 
42918382eadSSubhransu S. Prusty 		if (!(caps & AC_WCAP_DIGITAL))
43018382eadSSubhransu S. Prusty 			continue;
43118382eadSSubhransu S. Prusty 
43218382eadSSubhransu S. Prusty 		switch (type) {
43318382eadSSubhransu S. Prusty 
43418382eadSSubhransu S. Prusty 		case AC_WID_AUD_OUT:
43518382eadSSubhransu S. Prusty 			hdmi->cvt_nid[cvt_nid] = nid;
43618382eadSSubhransu S. Prusty 			cvt_nid++;
43718382eadSSubhransu S. Prusty 			break;
43818382eadSSubhransu S. Prusty 
43918382eadSSubhransu S. Prusty 		case AC_WID_PIN:
44018382eadSSubhransu S. Prusty 			hdmi->pin_nid[pin_nid] = nid;
44118382eadSSubhransu S. Prusty 			pin_nid++;
44218382eadSSubhransu S. Prusty 			break;
44318382eadSSubhransu S. Prusty 		}
44418382eadSSubhransu S. Prusty 	}
44518382eadSSubhransu S. Prusty 
44618382eadSSubhransu S. Prusty 	hdac->end_nid = nid;
44718382eadSSubhransu S. Prusty 
44818382eadSSubhransu S. Prusty 	if (!pin_nid || !cvt_nid)
44918382eadSSubhransu S. Prusty 		return -EIO;
45018382eadSSubhransu S. Prusty 
45118382eadSSubhransu S. Prusty 	/*
45218382eadSSubhransu S. Prusty 	 * Currently on board only 1 pin and 1 converter is enabled for
45318382eadSSubhransu S. Prusty 	 * simplification, more will be added eventually
45418382eadSSubhransu S. Prusty 	 * So using fixed map for dai_id:pin:cvt
45518382eadSSubhransu S. Prusty 	 */
45618382eadSSubhransu S. Prusty 	return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0],
45718382eadSSubhransu S. Prusty 			hdmi->cvt_nid[0], 0);
45818382eadSSubhransu S. Prusty }
45918382eadSSubhransu S. Prusty 
46018382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec)
46118382eadSSubhransu S. Prusty {
46218382eadSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
46318382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
46418382eadSSubhransu S. Prusty 	struct snd_soc_dapm_context *dapm =
46518382eadSSubhransu S. Prusty 		snd_soc_component_get_dapm(&codec->component);
46618382eadSSubhransu S. Prusty 
46718382eadSSubhransu S. Prusty 	edev->scodec = codec;
46818382eadSSubhransu S. Prusty 
46918382eadSSubhransu S. Prusty 	create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
47018382eadSSubhransu S. Prusty 
47118382eadSSubhransu S. Prusty 	/* Imp: Store the card pointer in hda_codec */
47218382eadSSubhransu S. Prusty 	edev->card = dapm->card->snd_card;
47318382eadSSubhransu S. Prusty 
474e342ac08SSubhransu S. Prusty 	/*
475e342ac08SSubhransu S. Prusty 	 * hdac_device core already sets the state to active and calls
476e342ac08SSubhransu S. Prusty 	 * get_noresume. So enable runtime and set the device to suspend.
477e342ac08SSubhransu S. Prusty 	 */
478e342ac08SSubhransu S. Prusty 	pm_runtime_enable(&edev->hdac.dev);
479e342ac08SSubhransu S. Prusty 	pm_runtime_put(&edev->hdac.dev);
480e342ac08SSubhransu S. Prusty 	pm_runtime_suspend(&edev->hdac.dev);
481e342ac08SSubhransu S. Prusty 
482e342ac08SSubhransu S. Prusty 	return 0;
483e342ac08SSubhransu S. Prusty }
484e342ac08SSubhransu S. Prusty 
485e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec)
486e342ac08SSubhransu S. Prusty {
487e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
488e342ac08SSubhransu S. Prusty 
489e342ac08SSubhransu S. Prusty 	pm_runtime_disable(&edev->hdac.dev);
49018382eadSSubhransu S. Prusty 	return 0;
49118382eadSSubhransu S. Prusty }
49218382eadSSubhransu S. Prusty 
49318382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = {
49418382eadSSubhransu S. Prusty 	.probe		= hdmi_codec_probe,
495e342ac08SSubhransu S. Prusty 	.remove		= hdmi_codec_remove,
49618382eadSSubhransu S. Prusty 	.idle_bias_off	= true,
49718382eadSSubhransu S. Prusty };
49818382eadSSubhransu S. Prusty 
499b0362adbSSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = {
500b0362adbSSubhransu S. Prusty 	.startup = hdac_hdmi_pcm_open,
501b0362adbSSubhransu S. Prusty 	.shutdown = hdac_hdmi_pcm_close,
502b0362adbSSubhransu S. Prusty 	.hw_params = hdac_hdmi_set_hw_params,
503b0362adbSSubhransu S. Prusty 	.prepare = hdac_hdmi_playback_prepare,
504b0362adbSSubhransu S. Prusty 	.hw_free = hdac_hdmi_playback_cleanup,
505b0362adbSSubhransu S. Prusty };
506b0362adbSSubhransu S. Prusty 
50718382eadSSubhransu S. Prusty static struct snd_soc_dai_driver hdmi_dais[] = {
50818382eadSSubhransu S. Prusty 	{	.name = "intel-hdmi-hif1",
50918382eadSSubhransu S. Prusty 		.playback = {
51018382eadSSubhransu S. Prusty 			.stream_name = "hif1",
51118382eadSSubhransu S. Prusty 			.channels_min = 2,
51218382eadSSubhransu S. Prusty 			.channels_max = 2,
51318382eadSSubhransu S. Prusty 			.rates = SNDRV_PCM_RATE_32000 |
51418382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
51518382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
51618382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
51718382eadSSubhransu S. Prusty 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
51818382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S20_3LE |
51918382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S24_LE |
52018382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S32_LE,
52118382eadSSubhransu S. Prusty 
52218382eadSSubhransu S. Prusty 		},
523b0362adbSSubhransu S. Prusty 		.ops = &hdmi_dai_ops,
52418382eadSSubhransu S. Prusty 	},
52518382eadSSubhransu S. Prusty };
52618382eadSSubhransu S. Prusty 
52718382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
52818382eadSSubhransu S. Prusty {
52918382eadSSubhransu S. Prusty 	struct hdac_device *codec = &edev->hdac;
53018382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi_priv;
53118382eadSSubhransu S. Prusty 	int ret = 0;
53218382eadSSubhransu S. Prusty 
53318382eadSSubhransu S. Prusty 	hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
53418382eadSSubhransu S. Prusty 	if (hdmi_priv == NULL)
53518382eadSSubhransu S. Prusty 		return -ENOMEM;
53618382eadSSubhransu S. Prusty 
53718382eadSSubhransu S. Prusty 	edev->private_data = hdmi_priv;
53818382eadSSubhransu S. Prusty 
53918382eadSSubhransu S. Prusty 	dev_set_drvdata(&codec->dev, edev);
54018382eadSSubhransu S. Prusty 
54118382eadSSubhransu S. Prusty 	ret = hdac_hdmi_parse_and_map_nid(edev);
54218382eadSSubhransu S. Prusty 	if (ret < 0)
54318382eadSSubhransu S. Prusty 		return ret;
54418382eadSSubhransu S. Prusty 
54518382eadSSubhransu S. Prusty 	/* ASoC specific initialization */
54618382eadSSubhransu S. Prusty 	return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
54718382eadSSubhransu S. Prusty 			hdmi_dais, ARRAY_SIZE(hdmi_dais));
54818382eadSSubhransu S. Prusty }
54918382eadSSubhransu S. Prusty 
55018382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
55118382eadSSubhransu S. Prusty {
55218382eadSSubhransu S. Prusty 	snd_soc_unregister_codec(&edev->hdac.dev);
55318382eadSSubhransu S. Prusty 
55418382eadSSubhransu S. Prusty 	return 0;
55518382eadSSubhransu S. Prusty }
55618382eadSSubhransu S. Prusty 
557e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM
558e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev)
559e342ac08SSubhransu S. Prusty {
560e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
561e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
562e342ac08SSubhransu S. Prusty 
563e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
564e342ac08SSubhransu S. Prusty 
565e342ac08SSubhransu S. Prusty 	/* Power down afg */
566e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
567e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
568e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
569e342ac08SSubhransu S. Prusty 
570e342ac08SSubhransu S. Prusty 	return 0;
571e342ac08SSubhransu S. Prusty }
572e342ac08SSubhransu S. Prusty 
573e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev)
574e342ac08SSubhransu S. Prusty {
575e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
576e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
577e342ac08SSubhransu S. Prusty 
578e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
579e342ac08SSubhransu S. Prusty 
580e342ac08SSubhransu S. Prusty 	/* Power up afg */
581e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
582e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
583e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
584e342ac08SSubhransu S. Prusty 
585e342ac08SSubhransu S. Prusty 	return 0;
586e342ac08SSubhransu S. Prusty }
587e342ac08SSubhransu S. Prusty #else
588e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL
589e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL
590e342ac08SSubhransu S. Prusty #endif
591e342ac08SSubhransu S. Prusty 
592e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = {
593e342ac08SSubhransu S. Prusty 	SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
594e342ac08SSubhransu S. Prusty };
595e342ac08SSubhransu S. Prusty 
59618382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = {
59718382eadSSubhransu S. Prusty 	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
59818382eadSSubhransu S. Prusty 	{}
59918382eadSSubhransu S. Prusty };
60018382eadSSubhransu S. Prusty 
60118382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
60218382eadSSubhransu S. Prusty 
60318382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = {
60418382eadSSubhransu S. Prusty 	. hdac = {
60518382eadSSubhransu S. Prusty 		.driver = {
60618382eadSSubhransu S. Prusty 			.name   = "HDMI HDA Codec",
607e342ac08SSubhransu S. Prusty 			.pm = &hdac_hdmi_pm,
60818382eadSSubhransu S. Prusty 		},
60918382eadSSubhransu S. Prusty 		.id_table       = hdmi_list,
61018382eadSSubhransu S. Prusty 	},
61118382eadSSubhransu S. Prusty 	.probe          = hdac_hdmi_dev_probe,
61218382eadSSubhransu S. Prusty 	.remove         = hdac_hdmi_dev_remove,
61318382eadSSubhransu S. Prusty };
61418382eadSSubhransu S. Prusty 
61518382eadSSubhransu S. Prusty static int __init hdmi_init(void)
61618382eadSSubhransu S. Prusty {
61718382eadSSubhransu S. Prusty 	return snd_hda_ext_driver_register(&hdmi_driver);
61818382eadSSubhransu S. Prusty }
61918382eadSSubhransu S. Prusty 
62018382eadSSubhransu S. Prusty static void __exit hdmi_exit(void)
62118382eadSSubhransu S. Prusty {
62218382eadSSubhransu S. Prusty 	snd_hda_ext_driver_unregister(&hdmi_driver);
62318382eadSSubhransu S. Prusty }
62418382eadSSubhransu S. Prusty 
62518382eadSSubhransu S. Prusty module_init(hdmi_init);
62618382eadSSubhransu S. Prusty module_exit(hdmi_exit);
62718382eadSSubhransu S. Prusty 
62818382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2");
62918382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec");
63018382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
63118382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
632