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