xref: /openbmc/linux/sound/soc/codecs/hdac_hdmi.c (revision e342ac08d0d57be81e5defb131f014b4ce27b107)
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>
2418382eadSSubhransu S. Prusty #include <sound/pcm_params.h>
2518382eadSSubhransu S. Prusty #include <sound/soc.h>
2618382eadSSubhransu S. Prusty #include <sound/hdaudio_ext.h>
2718382eadSSubhransu S. Prusty #include "../../hda/local.h"
2818382eadSSubhransu S. Prusty 
2918382eadSSubhransu S. Prusty #define PIN_OUT			(AC_PINCTL_OUT_EN)
3018382eadSSubhransu S. Prusty #define HDA_MAX_CONNECTIONS     32
3118382eadSSubhransu S. Prusty 
3218382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params {
3318382eadSSubhransu S. Prusty 	unsigned int channels_min;
3418382eadSSubhransu S. Prusty 	unsigned int channels_max;
3518382eadSSubhransu S. Prusty 	u32 rates;
3618382eadSSubhransu S. Prusty 	u64 formats;
3718382eadSSubhransu S. Prusty 	unsigned int maxbps;
3818382eadSSubhransu S. Prusty };
3918382eadSSubhransu S. Prusty 
4018382eadSSubhransu S. Prusty struct hdac_hdmi_cvt {
4118382eadSSubhransu S. Prusty 	hda_nid_t nid;
4218382eadSSubhransu S. Prusty 	struct hdac_hdmi_cvt_params params;
4318382eadSSubhransu S. Prusty };
4418382eadSSubhransu S. Prusty 
4518382eadSSubhransu S. Prusty struct hdac_hdmi_pin {
4618382eadSSubhransu S. Prusty 	hda_nid_t nid;
4718382eadSSubhransu S. Prusty 	int num_mux_nids;
4818382eadSSubhransu S. Prusty 	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
4918382eadSSubhransu S. Prusty };
5018382eadSSubhransu S. Prusty 
5118382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map {
5218382eadSSubhransu S. Prusty 	int dai_id;
5318382eadSSubhransu S. Prusty 	struct hdac_hdmi_pin pin;
5418382eadSSubhransu S. Prusty 	struct hdac_hdmi_cvt cvt;
5518382eadSSubhransu S. Prusty };
5618382eadSSubhransu S. Prusty 
5718382eadSSubhransu S. Prusty struct hdac_hdmi_priv {
5818382eadSSubhransu S. Prusty 	hda_nid_t pin_nid[3];
5918382eadSSubhransu S. Prusty 	hda_nid_t cvt_nid[3];
6018382eadSSubhransu S. Prusty 	struct hdac_hdmi_dai_pin_map dai_map[3];
6118382eadSSubhransu S. Prusty };
6218382eadSSubhransu S. Prusty 
63*e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
64*e342ac08SSubhransu S. Prusty {
65*e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = container_of(dev, struct hdac_device, dev);
66*e342ac08SSubhransu S. Prusty 
67*e342ac08SSubhransu S. Prusty 	return container_of(hdac, struct hdac_ext_device, hdac);
68*e342ac08SSubhransu S. Prusty }
69*e342ac08SSubhransu S. Prusty 
7018382eadSSubhransu S. Prusty static int
7118382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
7218382eadSSubhransu S. Prusty {
7318382eadSSubhransu S. Prusty 	int err;
7418382eadSSubhransu S. Prusty 
7518382eadSSubhransu S. Prusty 	/* Only stereo supported as of now */
7618382eadSSubhransu S. Prusty 	cvt->params.channels_min = cvt->params.channels_max = 2;
7718382eadSSubhransu S. Prusty 
7818382eadSSubhransu S. Prusty 	err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
7918382eadSSubhransu S. Prusty 			&cvt->params.rates,
8018382eadSSubhransu S. Prusty 			&cvt->params.formats,
8118382eadSSubhransu S. Prusty 			&cvt->params.maxbps);
8218382eadSSubhransu S. Prusty 	if (err < 0)
8318382eadSSubhransu S. Prusty 		dev_err(&hdac->dev,
8418382eadSSubhransu S. Prusty 			"Failed to query pcm params for nid %d: %d\n",
8518382eadSSubhransu S. Prusty 			cvt->nid, err);
8618382eadSSubhransu S. Prusty 
8718382eadSSubhransu S. Prusty 	return err;
8818382eadSSubhransu S. Prusty }
8918382eadSSubhransu S. Prusty 
9018382eadSSubhransu S. Prusty static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
9118382eadSSubhransu S. Prusty 					struct hdac_hdmi_pin *pin)
9218382eadSSubhransu S. Prusty {
9318382eadSSubhransu S. Prusty 	if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
9418382eadSSubhransu S. Prusty 		dev_warn(&hdac->hdac.dev,
9518382eadSSubhransu S. Prusty 			"HDMI: pin %d wcaps %#x does not support connection list\n",
9618382eadSSubhransu S. Prusty 			pin->nid, get_wcaps(&hdac->hdac, pin->nid));
9718382eadSSubhransu S. Prusty 		return -EINVAL;
9818382eadSSubhransu S. Prusty 	}
9918382eadSSubhransu S. Prusty 
10018382eadSSubhransu S. Prusty 	pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
10118382eadSSubhransu S. Prusty 			pin->mux_nids, HDA_MAX_CONNECTIONS);
10218382eadSSubhransu S. Prusty 	if (pin->num_mux_nids == 0) {
10318382eadSSubhransu S. Prusty 		dev_err(&hdac->hdac.dev, "No connections found\n");
10418382eadSSubhransu S. Prusty 		return -ENODEV;
10518382eadSSubhransu S. Prusty 	}
10618382eadSSubhransu S. Prusty 
10718382eadSSubhransu S. Prusty 	return pin->num_mux_nids;
10818382eadSSubhransu S. Prusty }
10918382eadSSubhransu S. Prusty 
11018382eadSSubhransu S. Prusty static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
11118382eadSSubhransu S. Prusty 				enum snd_soc_dapm_type id,
11218382eadSSubhransu S. Prusty 				const char *wname, const char *stream)
11318382eadSSubhransu S. Prusty {
11418382eadSSubhransu S. Prusty 	w->id = id;
11518382eadSSubhransu S. Prusty 	w->name = wname;
11618382eadSSubhransu S. Prusty 	w->sname = stream;
11718382eadSSubhransu S. Prusty 	w->reg = SND_SOC_NOPM;
11818382eadSSubhransu S. Prusty 	w->shift = 0;
11918382eadSSubhransu S. Prusty 	w->kcontrol_news = NULL;
12018382eadSSubhransu S. Prusty 	w->num_kcontrols = 0;
12118382eadSSubhransu S. Prusty 	w->priv = NULL;
12218382eadSSubhransu S. Prusty }
12318382eadSSubhransu S. Prusty 
12418382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
12518382eadSSubhransu S. Prusty 		const char *sink, const char *control, const char *src)
12618382eadSSubhransu S. Prusty {
12718382eadSSubhransu S. Prusty 	route->sink = sink;
12818382eadSSubhransu S. Prusty 	route->source = src;
12918382eadSSubhransu S. Prusty 	route->control = control;
13018382eadSSubhransu S. Prusty 	route->connected = NULL;
13118382eadSSubhransu S. Prusty }
13218382eadSSubhransu S. Prusty 
13318382eadSSubhransu S. Prusty static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
13418382eadSSubhransu S. Prusty 					struct hdac_hdmi_dai_pin_map *dai_map)
13518382eadSSubhransu S. Prusty {
13618382eadSSubhransu S. Prusty 	struct snd_soc_dapm_route route[1];
13718382eadSSubhransu S. Prusty 	struct snd_soc_dapm_widget widgets[2] = { {0} };
13818382eadSSubhransu S. Prusty 
13918382eadSSubhransu S. Prusty 	memset(&route, 0, sizeof(route));
14018382eadSSubhransu S. Prusty 
14118382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
14218382eadSSubhransu S. Prusty 			"hif1 Output", NULL);
14318382eadSSubhransu S. Prusty 	hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
14418382eadSSubhransu S. Prusty 			"Coverter 1", "hif1");
14518382eadSSubhransu S. Prusty 
14618382eadSSubhransu S. Prusty 	hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
14718382eadSSubhransu S. Prusty 
14818382eadSSubhransu S. Prusty 	snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
14918382eadSSubhransu S. Prusty 	snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
15018382eadSSubhransu S. Prusty }
15118382eadSSubhransu S. Prusty 
15218382eadSSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev,
15318382eadSSubhransu S. Prusty 			struct hdac_hdmi_dai_pin_map *dai_map,
15418382eadSSubhransu S. Prusty 			hda_nid_t pin_nid, hda_nid_t cvt_nid, int dai_id)
15518382eadSSubhransu S. Prusty {
15618382eadSSubhransu S. Prusty 	int ret;
15718382eadSSubhransu S. Prusty 
15818382eadSSubhransu S. Prusty 	dai_map->dai_id = dai_id;
15918382eadSSubhransu S. Prusty 	dai_map->pin.nid = pin_nid;
16018382eadSSubhransu S. Prusty 
16118382eadSSubhransu S. Prusty 	ret = hdac_hdmi_query_pin_connlist(edev, &dai_map->pin);
16218382eadSSubhransu S. Prusty 	if (ret < 0) {
16318382eadSSubhransu S. Prusty 		dev_err(&edev->hdac.dev,
16418382eadSSubhransu S. Prusty 			"Error querying connection list: %d\n", ret);
16518382eadSSubhransu S. Prusty 		return ret;
16618382eadSSubhransu S. Prusty 	}
16718382eadSSubhransu S. Prusty 
16818382eadSSubhransu S. Prusty 	dai_map->cvt.nid = cvt_nid;
16918382eadSSubhransu S. Prusty 
17018382eadSSubhransu S. Prusty 	/* Enable out path for this pin widget */
17118382eadSSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin_nid, 0,
17218382eadSSubhransu S. Prusty 			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17318382eadSSubhransu S. Prusty 
17418382eadSSubhransu S. Prusty 	/* Enable transmission */
17518382eadSSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt_nid, 0,
17618382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_1, 1);
17718382eadSSubhransu S. Prusty 
17818382eadSSubhransu S. Prusty 	/* Category Code (CC) to zero */
17918382eadSSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, cvt_nid, 0,
18018382eadSSubhransu S. Prusty 			AC_VERB_SET_DIGI_CONVERT_2, 0);
18118382eadSSubhransu S. Prusty 
18218382eadSSubhransu S. Prusty 	snd_hdac_codec_write(&edev->hdac, pin_nid, 0,
18318382eadSSubhransu S. Prusty 			AC_VERB_SET_CONNECT_SEL, 0);
18418382eadSSubhransu S. Prusty 
18518382eadSSubhransu S. Prusty 	return hdac_hdmi_query_cvt_params(&edev->hdac, &dai_map->cvt);
18618382eadSSubhransu S. Prusty }
18718382eadSSubhransu S. Prusty 
18818382eadSSubhransu S. Prusty /*
18918382eadSSubhransu S. Prusty  * Parse all nodes and store the cvt/pin nids in array
19018382eadSSubhransu S. Prusty  * Add one time initialization for pin and cvt widgets
19118382eadSSubhransu S. Prusty  */
19218382eadSSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
19318382eadSSubhransu S. Prusty {
19418382eadSSubhransu S. Prusty 	hda_nid_t nid;
19518382eadSSubhransu S. Prusty 	int i;
19618382eadSSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
19718382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
19818382eadSSubhransu S. Prusty 	int cvt_nid = 0, pin_nid = 0;
19918382eadSSubhransu S. Prusty 
20018382eadSSubhransu S. Prusty 	hdac->num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
20118382eadSSubhransu S. Prusty 	if (!nid || hdac->num_nodes < 0) {
20218382eadSSubhransu S. Prusty 		dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
20318382eadSSubhransu S. Prusty 		return -EINVAL;
20418382eadSSubhransu S. Prusty 	}
20518382eadSSubhransu S. Prusty 
20618382eadSSubhransu S. Prusty 	hdac->start_nid = nid;
20718382eadSSubhransu S. Prusty 
20818382eadSSubhransu S. Prusty 	for (i = 0; i < hdac->num_nodes; i++, nid++) {
20918382eadSSubhransu S. Prusty 		unsigned int caps;
21018382eadSSubhransu S. Prusty 		unsigned int type;
21118382eadSSubhransu S. Prusty 
21218382eadSSubhransu S. Prusty 		caps = get_wcaps(hdac, nid);
21318382eadSSubhransu S. Prusty 		type = get_wcaps_type(caps);
21418382eadSSubhransu S. Prusty 
21518382eadSSubhransu S. Prusty 		if (!(caps & AC_WCAP_DIGITAL))
21618382eadSSubhransu S. Prusty 			continue;
21718382eadSSubhransu S. Prusty 
21818382eadSSubhransu S. Prusty 		switch (type) {
21918382eadSSubhransu S. Prusty 
22018382eadSSubhransu S. Prusty 		case AC_WID_AUD_OUT:
22118382eadSSubhransu S. Prusty 			hdmi->cvt_nid[cvt_nid] = nid;
22218382eadSSubhransu S. Prusty 			cvt_nid++;
22318382eadSSubhransu S. Prusty 			break;
22418382eadSSubhransu S. Prusty 
22518382eadSSubhransu S. Prusty 		case AC_WID_PIN:
22618382eadSSubhransu S. Prusty 			hdmi->pin_nid[pin_nid] = nid;
22718382eadSSubhransu S. Prusty 			pin_nid++;
22818382eadSSubhransu S. Prusty 			break;
22918382eadSSubhransu S. Prusty 		}
23018382eadSSubhransu S. Prusty 	}
23118382eadSSubhransu S. Prusty 
23218382eadSSubhransu S. Prusty 	hdac->end_nid = nid;
23318382eadSSubhransu S. Prusty 
23418382eadSSubhransu S. Prusty 	if (!pin_nid || !cvt_nid)
23518382eadSSubhransu S. Prusty 		return -EIO;
23618382eadSSubhransu S. Prusty 
23718382eadSSubhransu S. Prusty 	/*
23818382eadSSubhransu S. Prusty 	 * Currently on board only 1 pin and 1 converter is enabled for
23918382eadSSubhransu S. Prusty 	 * simplification, more will be added eventually
24018382eadSSubhransu S. Prusty 	 * So using fixed map for dai_id:pin:cvt
24118382eadSSubhransu S. Prusty 	 */
24218382eadSSubhransu S. Prusty 	return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0],
24318382eadSSubhransu S. Prusty 			hdmi->cvt_nid[0], 0);
24418382eadSSubhransu S. Prusty }
24518382eadSSubhransu S. Prusty 
24618382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec)
24718382eadSSubhransu S. Prusty {
24818382eadSSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
24918382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi = edev->private_data;
25018382eadSSubhransu S. Prusty 	struct snd_soc_dapm_context *dapm =
25118382eadSSubhransu S. Prusty 		snd_soc_component_get_dapm(&codec->component);
25218382eadSSubhransu S. Prusty 
25318382eadSSubhransu S. Prusty 	edev->scodec = codec;
25418382eadSSubhransu S. Prusty 
25518382eadSSubhransu S. Prusty 	create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
25618382eadSSubhransu S. Prusty 
25718382eadSSubhransu S. Prusty 	/* Imp: Store the card pointer in hda_codec */
25818382eadSSubhransu S. Prusty 	edev->card = dapm->card->snd_card;
25918382eadSSubhransu S. Prusty 
260*e342ac08SSubhransu S. Prusty 	/*
261*e342ac08SSubhransu S. Prusty 	 * hdac_device core already sets the state to active and calls
262*e342ac08SSubhransu S. Prusty 	 * get_noresume. So enable runtime and set the device to suspend.
263*e342ac08SSubhransu S. Prusty 	 */
264*e342ac08SSubhransu S. Prusty 	pm_runtime_enable(&edev->hdac.dev);
265*e342ac08SSubhransu S. Prusty 	pm_runtime_put(&edev->hdac.dev);
266*e342ac08SSubhransu S. Prusty 	pm_runtime_suspend(&edev->hdac.dev);
267*e342ac08SSubhransu S. Prusty 
268*e342ac08SSubhransu S. Prusty 	return 0;
269*e342ac08SSubhransu S. Prusty }
270*e342ac08SSubhransu S. Prusty 
271*e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec)
272*e342ac08SSubhransu S. Prusty {
273*e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
274*e342ac08SSubhransu S. Prusty 
275*e342ac08SSubhransu S. Prusty 	pm_runtime_disable(&edev->hdac.dev);
27618382eadSSubhransu S. Prusty 	return 0;
27718382eadSSubhransu S. Prusty }
27818382eadSSubhransu S. Prusty 
27918382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = {
28018382eadSSubhransu S. Prusty 	.probe		= hdmi_codec_probe,
281*e342ac08SSubhransu S. Prusty 	.remove		= hdmi_codec_remove,
28218382eadSSubhransu S. Prusty 	.idle_bias_off	= true,
28318382eadSSubhransu S. Prusty };
28418382eadSSubhransu S. Prusty 
28518382eadSSubhransu S. Prusty static struct snd_soc_dai_driver hdmi_dais[] = {
28618382eadSSubhransu S. Prusty 	{	.name = "intel-hdmi-hif1",
28718382eadSSubhransu S. Prusty 		.playback = {
28818382eadSSubhransu S. Prusty 			.stream_name = "hif1",
28918382eadSSubhransu S. Prusty 			.channels_min = 2,
29018382eadSSubhransu S. Prusty 			.channels_max = 2,
29118382eadSSubhransu S. Prusty 			.rates = SNDRV_PCM_RATE_32000 |
29218382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
29318382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
29418382eadSSubhransu S. Prusty 				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
29518382eadSSubhransu S. Prusty 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
29618382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S20_3LE |
29718382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S24_LE |
29818382eadSSubhransu S. Prusty 				SNDRV_PCM_FMTBIT_S32_LE,
29918382eadSSubhransu S. Prusty 
30018382eadSSubhransu S. Prusty 		},
30118382eadSSubhransu S. Prusty 	},
30218382eadSSubhransu S. Prusty };
30318382eadSSubhransu S. Prusty 
30418382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
30518382eadSSubhransu S. Prusty {
30618382eadSSubhransu S. Prusty 	struct hdac_device *codec = &edev->hdac;
30718382eadSSubhransu S. Prusty 	struct hdac_hdmi_priv *hdmi_priv;
30818382eadSSubhransu S. Prusty 	int ret = 0;
30918382eadSSubhransu S. Prusty 
31018382eadSSubhransu S. Prusty 	hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
31118382eadSSubhransu S. Prusty 	if (hdmi_priv == NULL)
31218382eadSSubhransu S. Prusty 		return -ENOMEM;
31318382eadSSubhransu S. Prusty 
31418382eadSSubhransu S. Prusty 	edev->private_data = hdmi_priv;
31518382eadSSubhransu S. Prusty 
31618382eadSSubhransu S. Prusty 	dev_set_drvdata(&codec->dev, edev);
31718382eadSSubhransu S. Prusty 
31818382eadSSubhransu S. Prusty 	ret = hdac_hdmi_parse_and_map_nid(edev);
31918382eadSSubhransu S. Prusty 	if (ret < 0)
32018382eadSSubhransu S. Prusty 		return ret;
32118382eadSSubhransu S. Prusty 
32218382eadSSubhransu S. Prusty 	/* ASoC specific initialization */
32318382eadSSubhransu S. Prusty 	return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
32418382eadSSubhransu S. Prusty 			hdmi_dais, ARRAY_SIZE(hdmi_dais));
32518382eadSSubhransu S. Prusty }
32618382eadSSubhransu S. Prusty 
32718382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
32818382eadSSubhransu S. Prusty {
32918382eadSSubhransu S. Prusty 	snd_soc_unregister_codec(&edev->hdac.dev);
33018382eadSSubhransu S. Prusty 
33118382eadSSubhransu S. Prusty 	return 0;
33218382eadSSubhransu S. Prusty }
33318382eadSSubhransu S. Prusty 
334*e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM
335*e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev)
336*e342ac08SSubhransu S. Prusty {
337*e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
338*e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
339*e342ac08SSubhransu S. Prusty 
340*e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
341*e342ac08SSubhransu S. Prusty 
342*e342ac08SSubhransu S. Prusty 	/* Power down afg */
343*e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
344*e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
345*e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
346*e342ac08SSubhransu S. Prusty 
347*e342ac08SSubhransu S. Prusty 	return 0;
348*e342ac08SSubhransu S. Prusty }
349*e342ac08SSubhransu S. Prusty 
350*e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev)
351*e342ac08SSubhransu S. Prusty {
352*e342ac08SSubhransu S. Prusty 	struct hdac_ext_device *edev = to_hda_ext_device(dev);
353*e342ac08SSubhransu S. Prusty 	struct hdac_device *hdac = &edev->hdac;
354*e342ac08SSubhransu S. Prusty 
355*e342ac08SSubhransu S. Prusty 	dev_dbg(dev, "Enter: %s\n", __func__);
356*e342ac08SSubhransu S. Prusty 
357*e342ac08SSubhransu S. Prusty 	/* Power up afg */
358*e342ac08SSubhransu S. Prusty 	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
359*e342ac08SSubhransu S. Prusty 		snd_hdac_codec_write(hdac, hdac->afg, 0,
360*e342ac08SSubhransu S. Prusty 			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
361*e342ac08SSubhransu S. Prusty 
362*e342ac08SSubhransu S. Prusty 	return 0;
363*e342ac08SSubhransu S. Prusty }
364*e342ac08SSubhransu S. Prusty #else
365*e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL
366*e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL
367*e342ac08SSubhransu S. Prusty #endif
368*e342ac08SSubhransu S. Prusty 
369*e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = {
370*e342ac08SSubhransu S. Prusty 	SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
371*e342ac08SSubhransu S. Prusty };
372*e342ac08SSubhransu S. Prusty 
37318382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = {
37418382eadSSubhransu S. Prusty 	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
37518382eadSSubhransu S. Prusty 	{}
37618382eadSSubhransu S. Prusty };
37718382eadSSubhransu S. Prusty 
37818382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
37918382eadSSubhransu S. Prusty 
38018382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = {
38118382eadSSubhransu S. Prusty 	. hdac = {
38218382eadSSubhransu S. Prusty 		.driver = {
38318382eadSSubhransu S. Prusty 			.name   = "HDMI HDA Codec",
384*e342ac08SSubhransu S. Prusty 			.pm = &hdac_hdmi_pm,
38518382eadSSubhransu S. Prusty 		},
38618382eadSSubhransu S. Prusty 		.id_table       = hdmi_list,
38718382eadSSubhransu S. Prusty 	},
38818382eadSSubhransu S. Prusty 	.probe          = hdac_hdmi_dev_probe,
38918382eadSSubhransu S. Prusty 	.remove         = hdac_hdmi_dev_remove,
39018382eadSSubhransu S. Prusty };
39118382eadSSubhransu S. Prusty 
39218382eadSSubhransu S. Prusty static int __init hdmi_init(void)
39318382eadSSubhransu S. Prusty {
39418382eadSSubhransu S. Prusty 	return snd_hda_ext_driver_register(&hdmi_driver);
39518382eadSSubhransu S. Prusty }
39618382eadSSubhransu S. Prusty 
39718382eadSSubhransu S. Prusty static void __exit hdmi_exit(void)
39818382eadSSubhransu S. Prusty {
39918382eadSSubhransu S. Prusty 	snd_hda_ext_driver_unregister(&hdmi_driver);
40018382eadSSubhransu S. Prusty }
40118382eadSSubhransu S. Prusty 
40218382eadSSubhransu S. Prusty module_init(hdmi_init);
40318382eadSSubhransu S. Prusty module_exit(hdmi_exit);
40418382eadSSubhransu S. Prusty 
40518382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2");
40618382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec");
40718382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
40818382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
409