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/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_LOADER 40 static char *loadable_patch[HDA_MAX_CODECS]; 41 42 module_param_array_named(patch, loadable_patch, charp, NULL, 0444); 43 MODULE_PARM_DESC(patch, "Patch file array for Intel HD audio interface. The array index is the codec address."); 44 #endif 45 46 static int hdac_hda_dai_open(struct snd_pcm_substream *substream, 47 struct snd_soc_dai *dai); 48 static void hdac_hda_dai_close(struct snd_pcm_substream *substream, 49 struct snd_soc_dai *dai); 50 static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, 51 struct snd_soc_dai *dai); 52 static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, 53 struct snd_pcm_hw_params *params, 54 struct snd_soc_dai *dai); 55 static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, 56 struct snd_soc_dai *dai); 57 static int hdac_hda_dai_set_stream(struct snd_soc_dai *dai, void *stream, 58 int direction); 59 static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, 60 struct snd_soc_dai *dai); 61 62 static 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 71 static 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 .id = HDAC_HDMI_0_DAI_ID, 137 .name = "intel-hdmi-hifi1", 138 .ops = &hdac_hda_dai_ops, 139 .playback = { 140 .stream_name = "hifi1", 141 .channels_min = 1, 142 .channels_max = 32, 143 .rates = STUB_HDMI_RATES, 144 .formats = STUB_FORMATS, 145 .sig_bits = 24, 146 }, 147 }, 148 { 149 .id = HDAC_HDMI_1_DAI_ID, 150 .name = "intel-hdmi-hifi2", 151 .ops = &hdac_hda_dai_ops, 152 .playback = { 153 .stream_name = "hifi2", 154 .channels_min = 1, 155 .channels_max = 32, 156 .rates = STUB_HDMI_RATES, 157 .formats = STUB_FORMATS, 158 .sig_bits = 24, 159 }, 160 }, 161 { 162 .id = HDAC_HDMI_2_DAI_ID, 163 .name = "intel-hdmi-hifi3", 164 .ops = &hdac_hda_dai_ops, 165 .playback = { 166 .stream_name = "hifi3", 167 .channels_min = 1, 168 .channels_max = 32, 169 .rates = STUB_HDMI_RATES, 170 .formats = STUB_FORMATS, 171 .sig_bits = 24, 172 }, 173 }, 174 { 175 .id = HDAC_HDMI_3_DAI_ID, 176 .name = "intel-hdmi-hifi4", 177 .ops = &hdac_hda_dai_ops, 178 .playback = { 179 .stream_name = "hifi4", 180 .channels_min = 1, 181 .channels_max = 32, 182 .rates = STUB_HDMI_RATES, 183 .formats = STUB_FORMATS, 184 .sig_bits = 24, 185 }, 186 }, 187 188 }; 189 190 static int hdac_hda_dai_set_stream(struct snd_soc_dai *dai, 191 void *stream, int direction) 192 { 193 struct snd_soc_component *component = dai->component; 194 struct hdac_hda_priv *hda_pvt; 195 struct hdac_hda_pcm *pcm; 196 struct hdac_stream *hstream; 197 198 if (!stream) 199 return -EINVAL; 200 201 hda_pvt = snd_soc_component_get_drvdata(component); 202 pcm = &hda_pvt->pcm[dai->id]; 203 hstream = (struct hdac_stream *)stream; 204 205 pcm->stream_tag[direction] = hstream->stream_tag; 206 207 return 0; 208 } 209 210 static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, 211 struct snd_pcm_hw_params *params, 212 struct snd_soc_dai *dai) 213 { 214 struct snd_soc_component *component = dai->component; 215 struct hdac_hda_priv *hda_pvt; 216 unsigned int format_val; 217 unsigned int maxbps; 218 219 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 220 maxbps = dai->driver->playback.sig_bits; 221 else 222 maxbps = dai->driver->capture.sig_bits; 223 224 hda_pvt = snd_soc_component_get_drvdata(component); 225 format_val = snd_hdac_calc_stream_format(params_rate(params), 226 params_channels(params), 227 params_format(params), 228 maxbps, 229 0); 230 if (!format_val) { 231 dev_err(dai->dev, 232 "invalid format_val, rate=%d, ch=%d, format=%d, maxbps=%d\n", 233 params_rate(params), params_channels(params), 234 params_format(params), maxbps); 235 236 return -EINVAL; 237 } 238 239 hda_pvt->pcm[dai->id].format_val[substream->stream] = format_val; 240 return 0; 241 } 242 243 static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, 244 struct snd_soc_dai *dai) 245 { 246 struct snd_soc_component *component = dai->component; 247 struct hdac_hda_priv *hda_pvt; 248 struct hda_pcm_stream *hda_stream; 249 struct hda_pcm *pcm; 250 251 hda_pvt = snd_soc_component_get_drvdata(component); 252 pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); 253 if (!pcm) 254 return -EINVAL; 255 256 hda_stream = &pcm->stream[substream->stream]; 257 snd_hda_codec_cleanup(hda_pvt->codec, hda_stream, substream); 258 259 return 0; 260 } 261 262 static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, 263 struct snd_soc_dai *dai) 264 { 265 struct snd_soc_component *component = dai->component; 266 struct hda_pcm_stream *hda_stream; 267 struct hdac_hda_priv *hda_pvt; 268 struct hdac_device *hdev; 269 unsigned int format_val; 270 struct hda_pcm *pcm; 271 unsigned int stream; 272 int ret = 0; 273 274 hda_pvt = snd_soc_component_get_drvdata(component); 275 hdev = &hda_pvt->codec->core; 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(&hdev->dev, "codec prepare failed %d\n", ret); 289 290 return ret; 291 } 292 293 static 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 301 hda_pvt = snd_soc_component_get_drvdata(component); 302 pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); 303 if (!pcm) 304 return -EINVAL; 305 306 snd_hda_codec_pcm_get(pcm); 307 308 hda_stream = &pcm->stream[substream->stream]; 309 310 return hda_stream->ops.open(hda_stream, hda_pvt->codec, substream); 311 } 312 313 static void hdac_hda_dai_close(struct snd_pcm_substream *substream, 314 struct snd_soc_dai *dai) 315 { 316 struct snd_soc_component *component = dai->component; 317 struct hdac_hda_priv *hda_pvt; 318 struct hda_pcm_stream *hda_stream; 319 struct hda_pcm *pcm; 320 321 hda_pvt = snd_soc_component_get_drvdata(component); 322 pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); 323 if (!pcm) 324 return; 325 326 hda_stream = &pcm->stream[substream->stream]; 327 328 hda_stream->ops.close(hda_stream, hda_pvt->codec, substream); 329 330 snd_hda_codec_pcm_put(pcm); 331 } 332 333 static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, 334 struct snd_soc_dai *dai) 335 { 336 struct hda_codec *hcodec = hda_pvt->codec; 337 struct hda_pcm *cpcm; 338 const char *pcm_name; 339 340 /* 341 * map DAI ID to the closest matching PCM name, using the naming 342 * scheme used by hda-codec snd_hda_gen_build_pcms() and for 343 * HDMI in hda_codec patch_hdmi.c) 344 */ 345 346 switch (dai->id) { 347 case HDAC_ANALOG_DAI_ID: 348 pcm_name = "Analog"; 349 break; 350 case HDAC_DIGITAL_DAI_ID: 351 pcm_name = "Digital"; 352 break; 353 case HDAC_ALT_ANALOG_DAI_ID: 354 pcm_name = "Alt Analog"; 355 break; 356 case HDAC_HDMI_0_DAI_ID: 357 pcm_name = "HDMI 0"; 358 break; 359 case HDAC_HDMI_1_DAI_ID: 360 pcm_name = "HDMI 1"; 361 break; 362 case HDAC_HDMI_2_DAI_ID: 363 pcm_name = "HDMI 2"; 364 break; 365 case HDAC_HDMI_3_DAI_ID: 366 pcm_name = "HDMI 3"; 367 break; 368 default: 369 dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id); 370 return NULL; 371 } 372 373 list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) { 374 if (strstr(cpcm->name, pcm_name)) { 375 if (strcmp(pcm_name, "Analog") == 0) { 376 if (strstr(cpcm->name, "Alt Analog")) 377 continue; 378 } 379 return cpcm; 380 } 381 } 382 383 dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name); 384 return NULL; 385 } 386 387 static bool is_hdmi_codec(struct hda_codec *hcodec) 388 { 389 struct hda_pcm *cpcm; 390 391 list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) { 392 if (cpcm->pcm_type == HDA_PCM_TYPE_HDMI) 393 return true; 394 } 395 396 return false; 397 } 398 399 static int hdac_hda_codec_probe(struct snd_soc_component *component) 400 { 401 struct hdac_hda_priv *hda_pvt = 402 snd_soc_component_get_drvdata(component); 403 struct snd_soc_dapm_context *dapm = 404 snd_soc_component_get_dapm(component); 405 struct hdac_device *hdev = &hda_pvt->codec->core; 406 struct hda_codec *hcodec = hda_pvt->codec; 407 struct hdac_ext_link *hlink; 408 hda_codec_patch_t patch; 409 int ret; 410 411 hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); 412 if (!hlink) { 413 dev_err(&hdev->dev, "hdac link not found\n"); 414 return -EIO; 415 } 416 417 snd_hdac_ext_bus_link_get(hdev->bus, hlink); 418 419 /* 420 * Ensure any HDA display is powered at codec probe. 421 * After snd_hda_codec_device_new(), display power is 422 * managed by runtime PM. 423 */ 424 if (hda_pvt->need_display_power) 425 snd_hdac_display_power(hdev->bus, 426 HDA_CODEC_IDX_CONTROLLER, true); 427 428 ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card, 429 hdev->addr, hcodec, true); 430 if (ret < 0) { 431 dev_err(&hdev->dev, "failed to create hda codec %d\n", ret); 432 goto error_no_pm; 433 } 434 435 #ifdef CONFIG_SND_HDA_PATCH_LOADER 436 if (loadable_patch[hda_pvt->dev_index] && *loadable_patch[hda_pvt->dev_index]) { 437 const struct firmware *fw; 438 439 dev_info(&hdev->dev, "Applying patch firmware '%s'\n", 440 loadable_patch[hda_pvt->dev_index]); 441 ret = request_firmware(&fw, loadable_patch[hda_pvt->dev_index], 442 &hdev->dev); 443 if (ret < 0) 444 goto error_no_pm; 445 if (fw) { 446 ret = snd_hda_load_patch(hcodec->bus, fw->size, fw->data); 447 if (ret < 0) { 448 dev_err(&hdev->dev, "failed to load hda patch %d\n", ret); 449 goto error_no_pm; 450 } 451 release_firmware(fw); 452 } 453 } 454 #endif 455 /* 456 * Overwrite type to HDA_DEV_ASOC since it is a ASoC driver 457 * hda_codec.c will check this flag to determine if unregister 458 * device is needed. 459 */ 460 hdev->type = HDA_DEV_ASOC; 461 462 /* 463 * snd_hda_codec_device_new decrements the usage count so call get pm 464 * else the device will be powered off 465 */ 466 pm_runtime_get_noresume(&hdev->dev); 467 468 hcodec->bus->card = dapm->card->snd_card; 469 470 ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name); 471 if (ret < 0) { 472 dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name); 473 goto error_pm; 474 } 475 476 ret = snd_hdac_regmap_init(&hcodec->core); 477 if (ret < 0) { 478 dev_err(&hdev->dev, "regmap init failed\n"); 479 goto error_pm; 480 } 481 482 patch = (hda_codec_patch_t)hcodec->preset->driver_data; 483 if (patch) { 484 ret = patch(hcodec); 485 if (ret < 0) { 486 dev_err(&hdev->dev, "patch failed %d\n", ret); 487 goto error_regmap; 488 } 489 } else { 490 dev_dbg(&hdev->dev, "no patch file found\n"); 491 } 492 493 ret = snd_hda_codec_parse_pcms(hcodec); 494 if (ret < 0) { 495 dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); 496 goto error_patch; 497 } 498 499 /* HDMI controls need to be created in machine drivers */ 500 if (!is_hdmi_codec(hcodec)) { 501 ret = snd_hda_codec_build_controls(hcodec); 502 if (ret < 0) { 503 dev_err(&hdev->dev, "unable to create controls %d\n", 504 ret); 505 goto error_patch; 506 } 507 } 508 509 hcodec->core.lazy_cache = true; 510 511 if (hda_pvt->need_display_power) 512 snd_hdac_display_power(hdev->bus, 513 HDA_CODEC_IDX_CONTROLLER, false); 514 515 /* match for forbid call in snd_hda_codec_device_new() */ 516 pm_runtime_allow(&hdev->dev); 517 518 /* 519 * hdac_device core already sets the state to active and calls 520 * get_noresume. So enable runtime and set the device to suspend. 521 * pm_runtime_enable is also called during codec registeration 522 */ 523 pm_runtime_put(&hdev->dev); 524 pm_runtime_suspend(&hdev->dev); 525 526 return 0; 527 528 error_patch: 529 if (hcodec->patch_ops.free) 530 hcodec->patch_ops.free(hcodec); 531 error_regmap: 532 snd_hdac_regmap_exit(hdev); 533 error_pm: 534 pm_runtime_put(&hdev->dev); 535 error_no_pm: 536 snd_hdac_ext_bus_link_put(hdev->bus, hlink); 537 return ret; 538 } 539 540 static void hdac_hda_codec_remove(struct snd_soc_component *component) 541 { 542 struct hdac_hda_priv *hda_pvt = 543 snd_soc_component_get_drvdata(component); 544 struct hdac_device *hdev = &hda_pvt->codec->core; 545 struct hda_codec *codec = hda_pvt->codec; 546 struct hdac_ext_link *hlink = NULL; 547 548 hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); 549 if (!hlink) { 550 dev_err(&hdev->dev, "hdac link not found\n"); 551 return; 552 } 553 554 pm_runtime_disable(&hdev->dev); 555 snd_hdac_ext_bus_link_put(hdev->bus, hlink); 556 557 if (codec->patch_ops.free) 558 codec->patch_ops.free(codec); 559 560 snd_hda_codec_cleanup_for_unbind(codec); 561 } 562 563 static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = { 564 {"AIF1TX", NULL, "Codec Input Pin1"}, 565 {"AIF2TX", NULL, "Codec Input Pin2"}, 566 {"AIF3TX", NULL, "Codec Input Pin3"}, 567 568 {"Codec Output Pin1", NULL, "AIF1RX"}, 569 {"Codec Output Pin2", NULL, "AIF2RX"}, 570 {"Codec Output Pin3", NULL, "AIF3RX"}, 571 }; 572 573 static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = { 574 /* Audio Interface */ 575 SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0, 576 SND_SOC_NOPM, 0, 0), 577 SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0, 578 SND_SOC_NOPM, 0, 0), 579 SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0, 580 SND_SOC_NOPM, 0, 0), 581 SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0, 582 SND_SOC_NOPM, 0, 0), 583 SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0, 584 SND_SOC_NOPM, 0, 0), 585 SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0, 586 SND_SOC_NOPM, 0, 0), 587 588 /* Input Pins */ 589 SND_SOC_DAPM_INPUT("Codec Input Pin1"), 590 SND_SOC_DAPM_INPUT("Codec Input Pin2"), 591 SND_SOC_DAPM_INPUT("Codec Input Pin3"), 592 593 /* Output Pins */ 594 SND_SOC_DAPM_OUTPUT("Codec Output Pin1"), 595 SND_SOC_DAPM_OUTPUT("Codec Output Pin2"), 596 SND_SOC_DAPM_OUTPUT("Codec Output Pin3"), 597 }; 598 599 static const struct snd_soc_component_driver hdac_hda_codec = { 600 .probe = hdac_hda_codec_probe, 601 .remove = hdac_hda_codec_remove, 602 .dapm_widgets = hdac_hda_dapm_widgets, 603 .num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets), 604 .dapm_routes = hdac_hda_dapm_routes, 605 .num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes), 606 .idle_bias_on = false, 607 .endianness = 1, 608 }; 609 610 static int hdac_hda_dev_probe(struct hdac_device *hdev) 611 { 612 struct hdac_ext_link *hlink; 613 int ret; 614 615 /* hold the ref while we probe */ 616 hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); 617 if (!hlink) { 618 dev_err(&hdev->dev, "hdac link not found\n"); 619 return -EIO; 620 } 621 snd_hdac_ext_bus_link_get(hdev->bus, hlink); 622 623 /* ASoC specific initialization */ 624 ret = devm_snd_soc_register_component(&hdev->dev, 625 &hdac_hda_codec, hdac_hda_dais, 626 ARRAY_SIZE(hdac_hda_dais)); 627 if (ret < 0) { 628 dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret); 629 return ret; 630 } 631 632 snd_hdac_ext_bus_link_put(hdev->bus, hlink); 633 634 return ret; 635 } 636 637 static int hdac_hda_dev_remove(struct hdac_device *hdev) 638 { 639 /* 640 * Resources are freed in hdac_hda_codec_remove(). This 641 * function is kept to keep hda_codec_driver_remove() happy. 642 */ 643 return 0; 644 } 645 646 static struct hdac_ext_bus_ops hdac_ops = { 647 .hdev_attach = hdac_hda_dev_probe, 648 .hdev_detach = hdac_hda_dev_remove, 649 }; 650 651 struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void) 652 { 653 return &hdac_ops; 654 } 655 EXPORT_SYMBOL_GPL(snd_soc_hdac_hda_get_ops); 656 657 MODULE_LICENSE("GPL v2"); 658 MODULE_DESCRIPTION("ASoC Extensions for legacy HDA Drivers"); 659 MODULE_AUTHOR("Rakesh Ughreja<rakesh.a.ughreja@intel.com>"); 660