brintos

brintos / linux-shallow public Read only

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