cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hdac_hda.c (16770B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright(c) 2015-18 Intel Corporation.
      3
      4/*
      5 * hdac_hda.c - ASoC extensions to reuse the legacy HDA codec drivers
      6 * with ASoC platform drivers. These APIs are called by the legacy HDA
      7 * codec drivers using hdac_ext_bus_ops ops.
      8 */
      9
     10#include <linux/init.h>
     11#include <linux/delay.h>
     12#include <linux/module.h>
     13#include <linux/pm_runtime.h>
     14#include <sound/pcm_params.h>
     15#include <sound/soc.h>
     16#include <sound/hdaudio_ext.h>
     17#include <sound/hda_i915.h>
     18#include <sound/hda_codec.h>
     19#include <sound/hda_register.h>
     20
     21#include "hdac_hda.h"
     22
     23#define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S8 | \
     24			SNDRV_PCM_FMTBIT_U8 | \
     25			SNDRV_PCM_FMTBIT_S16_LE | \
     26			SNDRV_PCM_FMTBIT_U16_LE | \
     27			SNDRV_PCM_FMTBIT_S24_LE | \
     28			SNDRV_PCM_FMTBIT_U24_LE | \
     29			SNDRV_PCM_FMTBIT_S32_LE | \
     30			SNDRV_PCM_FMTBIT_U32_LE | \
     31			SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
     32
     33#define STUB_HDMI_RATES	(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
     34				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
     35				 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
     36				 SNDRV_PCM_RATE_192000)
     37
     38static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
     39			     struct snd_soc_dai *dai);
     40static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
     41			       struct snd_soc_dai *dai);
     42static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
     43				struct snd_soc_dai *dai);
     44static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream,
     45				  struct snd_pcm_hw_params *params,
     46				  struct snd_soc_dai *dai);
     47static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream,
     48				struct snd_soc_dai *dai);
     49static int hdac_hda_dai_set_stream(struct snd_soc_dai *dai, void *stream,
     50				   int direction);
     51static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
     52						 struct snd_soc_dai *dai);
     53
     54static const struct snd_soc_dai_ops hdac_hda_dai_ops = {
     55	.startup = hdac_hda_dai_open,
     56	.shutdown = hdac_hda_dai_close,
     57	.prepare = hdac_hda_dai_prepare,
     58	.hw_params = hdac_hda_dai_hw_params,
     59	.hw_free = hdac_hda_dai_hw_free,
     60	.set_stream = hdac_hda_dai_set_stream,
     61};
     62
     63static struct snd_soc_dai_driver hdac_hda_dais[] = {
     64{
     65	.id = HDAC_ANALOG_DAI_ID,
     66	.name = "Analog Codec DAI",
     67	.ops = &hdac_hda_dai_ops,
     68	.playback = {
     69		.stream_name	= "Analog Codec Playback",
     70		.channels_min	= 1,
     71		.channels_max	= 16,
     72		.rates		= SNDRV_PCM_RATE_8000_192000,
     73		.formats	= STUB_FORMATS,
     74		.sig_bits	= 24,
     75	},
     76	.capture = {
     77		.stream_name    = "Analog Codec Capture",
     78		.channels_min   = 1,
     79		.channels_max   = 16,
     80		.rates = SNDRV_PCM_RATE_8000_192000,
     81		.formats = STUB_FORMATS,
     82		.sig_bits = 24,
     83	},
     84},
     85{
     86	.id = HDAC_DIGITAL_DAI_ID,
     87	.name = "Digital Codec DAI",
     88	.ops = &hdac_hda_dai_ops,
     89	.playback = {
     90		.stream_name    = "Digital Codec Playback",
     91		.channels_min   = 1,
     92		.channels_max   = 16,
     93		.rates          = SNDRV_PCM_RATE_8000_192000,
     94		.formats        = STUB_FORMATS,
     95		.sig_bits = 24,
     96	},
     97	.capture = {
     98		.stream_name    = "Digital Codec Capture",
     99		.channels_min   = 1,
    100		.channels_max   = 16,
    101		.rates = SNDRV_PCM_RATE_8000_192000,
    102		.formats = STUB_FORMATS,
    103		.sig_bits = 24,
    104	},
    105},
    106{
    107	.id = HDAC_ALT_ANALOG_DAI_ID,
    108	.name = "Alt Analog Codec DAI",
    109	.ops = &hdac_hda_dai_ops,
    110	.playback = {
    111		.stream_name	= "Alt Analog Codec Playback",
    112		.channels_min	= 1,
    113		.channels_max	= 16,
    114		.rates		= SNDRV_PCM_RATE_8000_192000,
    115		.formats	= STUB_FORMATS,
    116		.sig_bits	= 24,
    117	},
    118	.capture = {
    119		.stream_name    = "Alt Analog Codec Capture",
    120		.channels_min   = 1,
    121		.channels_max   = 16,
    122		.rates = SNDRV_PCM_RATE_8000_192000,
    123		.formats = STUB_FORMATS,
    124		.sig_bits = 24,
    125	},
    126},
    127{
    128	.id = HDAC_HDMI_0_DAI_ID,
    129	.name = "intel-hdmi-hifi1",
    130	.ops = &hdac_hda_dai_ops,
    131	.playback = {
    132		.stream_name    = "hifi1",
    133		.channels_min   = 1,
    134		.channels_max   = 32,
    135		.rates          = STUB_HDMI_RATES,
    136		.formats        = STUB_FORMATS,
    137		.sig_bits = 24,
    138	},
    139},
    140{
    141	.id = HDAC_HDMI_1_DAI_ID,
    142	.name = "intel-hdmi-hifi2",
    143	.ops = &hdac_hda_dai_ops,
    144	.playback = {
    145		.stream_name    = "hifi2",
    146		.channels_min   = 1,
    147		.channels_max   = 32,
    148		.rates          = STUB_HDMI_RATES,
    149		.formats        = STUB_FORMATS,
    150		.sig_bits = 24,
    151	},
    152},
    153{
    154	.id = HDAC_HDMI_2_DAI_ID,
    155	.name = "intel-hdmi-hifi3",
    156	.ops = &hdac_hda_dai_ops,
    157	.playback = {
    158		.stream_name    = "hifi3",
    159		.channels_min   = 1,
    160		.channels_max   = 32,
    161		.rates          = STUB_HDMI_RATES,
    162		.formats        = STUB_FORMATS,
    163		.sig_bits = 24,
    164	},
    165},
    166{
    167	.id = HDAC_HDMI_3_DAI_ID,
    168	.name = "intel-hdmi-hifi4",
    169	.ops = &hdac_hda_dai_ops,
    170	.playback = {
    171		.stream_name    = "hifi4",
    172		.channels_min   = 1,
    173		.channels_max   = 32,
    174		.rates          = STUB_HDMI_RATES,
    175		.formats        = STUB_FORMATS,
    176		.sig_bits = 24,
    177	},
    178},
    179
    180};
    181
    182static int hdac_hda_dai_set_stream(struct snd_soc_dai *dai,
    183				   void *stream, int direction)
    184{
    185	struct snd_soc_component *component = dai->component;
    186	struct hdac_hda_priv *hda_pvt;
    187	struct hdac_hda_pcm *pcm;
    188	struct hdac_stream *hstream;
    189
    190	if (!stream)
    191		return -EINVAL;
    192
    193	hda_pvt = snd_soc_component_get_drvdata(component);
    194	pcm = &hda_pvt->pcm[dai->id];
    195	hstream = (struct hdac_stream *)stream;
    196
    197	pcm->stream_tag[direction] = hstream->stream_tag;
    198
    199	return 0;
    200}
    201
    202static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream,
    203				  struct snd_pcm_hw_params *params,
    204				  struct snd_soc_dai *dai)
    205{
    206	struct snd_soc_component *component = dai->component;
    207	struct hdac_hda_priv *hda_pvt;
    208	unsigned int format_val;
    209	unsigned int maxbps;
    210
    211	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    212		maxbps = dai->driver->playback.sig_bits;
    213	else
    214		maxbps = dai->driver->capture.sig_bits;
    215
    216	hda_pvt = snd_soc_component_get_drvdata(component);
    217	format_val = snd_hdac_calc_stream_format(params_rate(params),
    218						 params_channels(params),
    219						 params_format(params),
    220						 maxbps,
    221						 0);
    222	if (!format_val) {
    223		dev_err(dai->dev,
    224			"invalid format_val, rate=%d, ch=%d, format=%d, maxbps=%d\n",
    225			params_rate(params), params_channels(params),
    226			params_format(params), maxbps);
    227
    228		return -EINVAL;
    229	}
    230
    231	hda_pvt->pcm[dai->id].format_val[substream->stream] = format_val;
    232	return 0;
    233}
    234
    235static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream,
    236				struct snd_soc_dai *dai)
    237{
    238	struct snd_soc_component *component = dai->component;
    239	struct hdac_hda_priv *hda_pvt;
    240	struct hda_pcm_stream *hda_stream;
    241	struct hda_pcm *pcm;
    242
    243	hda_pvt = snd_soc_component_get_drvdata(component);
    244	pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
    245	if (!pcm)
    246		return -EINVAL;
    247
    248	hda_stream = &pcm->stream[substream->stream];
    249	snd_hda_codec_cleanup(&hda_pvt->codec, hda_stream, substream);
    250
    251	return 0;
    252}
    253
    254static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
    255				struct snd_soc_dai *dai)
    256{
    257	struct snd_soc_component *component = dai->component;
    258	struct hda_pcm_stream *hda_stream;
    259	struct hdac_hda_priv *hda_pvt;
    260	struct hdac_device *hdev;
    261	unsigned int format_val;
    262	struct hda_pcm *pcm;
    263	unsigned int stream;
    264	int ret = 0;
    265
    266	hda_pvt = snd_soc_component_get_drvdata(component);
    267	hdev = &hda_pvt->codec.core;
    268	pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
    269	if (!pcm)
    270		return -EINVAL;
    271
    272	hda_stream = &pcm->stream[substream->stream];
    273
    274	stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream];
    275	format_val = hda_pvt->pcm[dai->id].format_val[substream->stream];
    276
    277	ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream,
    278				    stream, format_val, substream);
    279	if (ret < 0)
    280		dev_err(&hdev->dev, "codec prepare failed %d\n", ret);
    281
    282	return ret;
    283}
    284
    285static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
    286			     struct snd_soc_dai *dai)
    287{
    288	struct snd_soc_component *component = dai->component;
    289	struct hdac_hda_priv *hda_pvt;
    290	struct hda_pcm_stream *hda_stream;
    291	struct hda_pcm *pcm;
    292
    293	hda_pvt = snd_soc_component_get_drvdata(component);
    294	pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
    295	if (!pcm)
    296		return -EINVAL;
    297
    298	snd_hda_codec_pcm_get(pcm);
    299
    300	hda_stream = &pcm->stream[substream->stream];
    301
    302	return hda_stream->ops.open(hda_stream, &hda_pvt->codec, substream);
    303}
    304
    305static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
    306			       struct snd_soc_dai *dai)
    307{
    308	struct snd_soc_component *component = dai->component;
    309	struct hdac_hda_priv *hda_pvt;
    310	struct hda_pcm_stream *hda_stream;
    311	struct hda_pcm *pcm;
    312
    313	hda_pvt = snd_soc_component_get_drvdata(component);
    314	pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
    315	if (!pcm)
    316		return;
    317
    318	hda_stream = &pcm->stream[substream->stream];
    319
    320	hda_stream->ops.close(hda_stream, &hda_pvt->codec, substream);
    321
    322	snd_hda_codec_pcm_put(pcm);
    323}
    324
    325static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
    326						 struct snd_soc_dai *dai)
    327{
    328	struct hda_codec *hcodec = &hda_pvt->codec;
    329	struct hda_pcm *cpcm;
    330	const char *pcm_name;
    331
    332	/*
    333	 * map DAI ID to the closest matching PCM name, using the naming
    334	 * scheme used by hda-codec snd_hda_gen_build_pcms() and for
    335	 * HDMI in hda_codec patch_hdmi.c)
    336	 */
    337
    338	switch (dai->id) {
    339	case HDAC_ANALOG_DAI_ID:
    340		pcm_name = "Analog";
    341		break;
    342	case HDAC_DIGITAL_DAI_ID:
    343		pcm_name = "Digital";
    344		break;
    345	case HDAC_ALT_ANALOG_DAI_ID:
    346		pcm_name = "Alt Analog";
    347		break;
    348	case HDAC_HDMI_0_DAI_ID:
    349		pcm_name = "HDMI 0";
    350		break;
    351	case HDAC_HDMI_1_DAI_ID:
    352		pcm_name = "HDMI 1";
    353		break;
    354	case HDAC_HDMI_2_DAI_ID:
    355		pcm_name = "HDMI 2";
    356		break;
    357	case HDAC_HDMI_3_DAI_ID:
    358		pcm_name = "HDMI 3";
    359		break;
    360	default:
    361		dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id);
    362		return NULL;
    363	}
    364
    365	list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) {
    366		if (strstr(cpcm->name, pcm_name)) {
    367			if (strcmp(pcm_name, "Analog") == 0) {
    368				if (strstr(cpcm->name, "Alt Analog"))
    369					continue;
    370			}
    371			return cpcm;
    372		}
    373	}
    374
    375	dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name);
    376	return NULL;
    377}
    378
    379static bool is_hdmi_codec(struct hda_codec *hcodec)
    380{
    381	struct hda_pcm *cpcm;
    382
    383	list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) {
    384		if (cpcm->pcm_type == HDA_PCM_TYPE_HDMI)
    385			return true;
    386	}
    387
    388	return false;
    389}
    390
    391static int hdac_hda_codec_probe(struct snd_soc_component *component)
    392{
    393	struct hdac_hda_priv *hda_pvt =
    394			snd_soc_component_get_drvdata(component);
    395	struct snd_soc_dapm_context *dapm =
    396			snd_soc_component_get_dapm(component);
    397	struct hdac_device *hdev = &hda_pvt->codec.core;
    398	struct hda_codec *hcodec = &hda_pvt->codec;
    399	struct hdac_ext_link *hlink;
    400	hda_codec_patch_t patch;
    401	int ret;
    402
    403	hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
    404	if (!hlink) {
    405		dev_err(&hdev->dev, "hdac link not found\n");
    406		return -EIO;
    407	}
    408
    409	snd_hdac_ext_bus_link_get(hdev->bus, hlink);
    410
    411	/*
    412	 * Ensure any HDA display is powered at codec probe.
    413	 * After snd_hda_codec_device_new(), display power is
    414	 * managed by runtime PM.
    415	 */
    416	if (hda_pvt->need_display_power)
    417		snd_hdac_display_power(hdev->bus,
    418				       HDA_CODEC_IDX_CONTROLLER, true);
    419
    420	ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card,
    421				       hdev->addr, hcodec, true);
    422	if (ret < 0) {
    423		dev_err(&hdev->dev, "failed to create hda codec %d\n", ret);
    424		goto error_no_pm;
    425	}
    426	/*
    427	 * Overwrite type to HDA_DEV_ASOC since it is a ASoC driver
    428	 * hda_codec.c will check this flag to determine if unregister
    429	 * device is needed.
    430	 */
    431	hdev->type = HDA_DEV_ASOC;
    432
    433	/*
    434	 * snd_hda_codec_device_new decrements the usage count so call get pm
    435	 * else the device will be powered off
    436	 */
    437	pm_runtime_get_noresume(&hdev->dev);
    438
    439	hcodec->bus->card = dapm->card->snd_card;
    440
    441	ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name);
    442	if (ret < 0) {
    443		dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name);
    444		goto error_pm;
    445	}
    446
    447	ret = snd_hdac_regmap_init(&hcodec->core);
    448	if (ret < 0) {
    449		dev_err(&hdev->dev, "regmap init failed\n");
    450		goto error_pm;
    451	}
    452
    453	patch = (hda_codec_patch_t)hcodec->preset->driver_data;
    454	if (patch) {
    455		ret = patch(hcodec);
    456		if (ret < 0) {
    457			dev_err(&hdev->dev, "patch failed %d\n", ret);
    458			goto error_regmap;
    459		}
    460	} else {
    461		dev_dbg(&hdev->dev, "no patch file found\n");
    462	}
    463
    464	/* configure codec for 1:1 PCM:DAI mapping */
    465	hcodec->mst_no_extra_pcms = 1;
    466
    467	ret = snd_hda_codec_parse_pcms(hcodec);
    468	if (ret < 0) {
    469		dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
    470		goto error_patch;
    471	}
    472
    473	/* HDMI controls need to be created in machine drivers */
    474	if (!is_hdmi_codec(hcodec)) {
    475		ret = snd_hda_codec_build_controls(hcodec);
    476		if (ret < 0) {
    477			dev_err(&hdev->dev, "unable to create controls %d\n",
    478				ret);
    479			goto error_patch;
    480		}
    481	}
    482
    483	hcodec->core.lazy_cache = true;
    484
    485	if (hda_pvt->need_display_power)
    486		snd_hdac_display_power(hdev->bus,
    487				       HDA_CODEC_IDX_CONTROLLER, false);
    488
    489	/* match for forbid call in snd_hda_codec_device_new() */
    490	pm_runtime_allow(&hdev->dev);
    491
    492	/*
    493	 * hdac_device core already sets the state to active and calls
    494	 * get_noresume. So enable runtime and set the device to suspend.
    495	 * pm_runtime_enable is also called during codec registeration
    496	 */
    497	pm_runtime_put(&hdev->dev);
    498	pm_runtime_suspend(&hdev->dev);
    499
    500	return 0;
    501
    502error_patch:
    503	if (hcodec->patch_ops.free)
    504		hcodec->patch_ops.free(hcodec);
    505error_regmap:
    506	snd_hdac_regmap_exit(hdev);
    507error_pm:
    508	pm_runtime_put(&hdev->dev);
    509error_no_pm:
    510	snd_hdac_ext_bus_link_put(hdev->bus, hlink);
    511	return ret;
    512}
    513
    514static void hdac_hda_codec_remove(struct snd_soc_component *component)
    515{
    516	struct hdac_hda_priv *hda_pvt =
    517		      snd_soc_component_get_drvdata(component);
    518	struct hdac_device *hdev = &hda_pvt->codec.core;
    519	struct hda_codec *codec = &hda_pvt->codec;
    520	struct hdac_ext_link *hlink = NULL;
    521
    522	hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
    523	if (!hlink) {
    524		dev_err(&hdev->dev, "hdac link not found\n");
    525		return;
    526	}
    527
    528	pm_runtime_disable(&hdev->dev);
    529	snd_hdac_ext_bus_link_put(hdev->bus, hlink);
    530
    531	if (codec->patch_ops.free)
    532		codec->patch_ops.free(codec);
    533
    534	snd_hda_codec_cleanup_for_unbind(codec);
    535}
    536
    537static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = {
    538	{"AIF1TX", NULL, "Codec Input Pin1"},
    539	{"AIF2TX", NULL, "Codec Input Pin2"},
    540	{"AIF3TX", NULL, "Codec Input Pin3"},
    541
    542	{"Codec Output Pin1", NULL, "AIF1RX"},
    543	{"Codec Output Pin2", NULL, "AIF2RX"},
    544	{"Codec Output Pin3", NULL, "AIF3RX"},
    545};
    546
    547static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = {
    548	/* Audio Interface */
    549	SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0,
    550			    SND_SOC_NOPM, 0, 0),
    551	SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0,
    552			    SND_SOC_NOPM, 0, 0),
    553	SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0,
    554			    SND_SOC_NOPM, 0, 0),
    555	SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0,
    556			     SND_SOC_NOPM, 0, 0),
    557	SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0,
    558			     SND_SOC_NOPM, 0, 0),
    559	SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0,
    560			     SND_SOC_NOPM, 0, 0),
    561
    562	/* Input Pins */
    563	SND_SOC_DAPM_INPUT("Codec Input Pin1"),
    564	SND_SOC_DAPM_INPUT("Codec Input Pin2"),
    565	SND_SOC_DAPM_INPUT("Codec Input Pin3"),
    566
    567	/* Output Pins */
    568	SND_SOC_DAPM_OUTPUT("Codec Output Pin1"),
    569	SND_SOC_DAPM_OUTPUT("Codec Output Pin2"),
    570	SND_SOC_DAPM_OUTPUT("Codec Output Pin3"),
    571};
    572
    573static const struct snd_soc_component_driver hdac_hda_codec = {
    574	.probe			= hdac_hda_codec_probe,
    575	.remove			= hdac_hda_codec_remove,
    576	.dapm_widgets		= hdac_hda_dapm_widgets,
    577	.num_dapm_widgets	= ARRAY_SIZE(hdac_hda_dapm_widgets),
    578	.dapm_routes		= hdac_hda_dapm_routes,
    579	.num_dapm_routes	= ARRAY_SIZE(hdac_hda_dapm_routes),
    580	.idle_bias_on		= false,
    581	.endianness		= 1,
    582};
    583
    584static int hdac_hda_dev_probe(struct hdac_device *hdev)
    585{
    586	struct hdac_ext_link *hlink;
    587	struct hdac_hda_priv *hda_pvt;
    588	int ret;
    589
    590	/* hold the ref while we probe */
    591	hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
    592	if (!hlink) {
    593		dev_err(&hdev->dev, "hdac link not found\n");
    594		return -EIO;
    595	}
    596	snd_hdac_ext_bus_link_get(hdev->bus, hlink);
    597
    598	hda_pvt = hdac_to_hda_priv(hdev);
    599	if (!hda_pvt)
    600		return -ENOMEM;
    601
    602	/* ASoC specific initialization */
    603	ret = devm_snd_soc_register_component(&hdev->dev,
    604					 &hdac_hda_codec, hdac_hda_dais,
    605					 ARRAY_SIZE(hdac_hda_dais));
    606	if (ret < 0) {
    607		dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret);
    608		return ret;
    609	}
    610
    611	dev_set_drvdata(&hdev->dev, hda_pvt);
    612	snd_hdac_ext_bus_link_put(hdev->bus, hlink);
    613
    614	return ret;
    615}
    616
    617static int hdac_hda_dev_remove(struct hdac_device *hdev)
    618{
    619	/*
    620	 * Resources are freed in hdac_hda_codec_remove(). This
    621	 * function is kept to keep hda_codec_driver_remove() happy.
    622	 */
    623	return 0;
    624}
    625
    626static struct hdac_ext_bus_ops hdac_ops = {
    627	.hdev_attach = hdac_hda_dev_probe,
    628	.hdev_detach = hdac_hda_dev_remove,
    629};
    630
    631struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void)
    632{
    633	return &hdac_ops;
    634}
    635EXPORT_SYMBOL_GPL(snd_soc_hdac_hda_get_ops);
    636
    637MODULE_LICENSE("GPL v2");
    638MODULE_DESCRIPTION("ASoC Extensions for legacy HDA Drivers");
    639MODULE_AUTHOR("Rakesh Ughreja<rakesh.a.ughreja@intel.com>");