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        .id = HDAC_HDMI_3_DAI_ID,
 169        .name = "intel-hdmi-hifi4",
 170        .ops = &hdac_hda_dai_ops,
 171        .playback = {
 172                .stream_name    = "hifi4",
 173                .channels_min   = 1,
 174                .channels_max   = 32,
 175                .rates          = STUB_HDMI_RATES,
 176                .formats        = STUB_FORMATS,
 177                .sig_bits = 24,
 178        },
 179},
 180
 181};
 182
 183static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
 184                                     unsigned int tx_mask, unsigned int rx_mask,
 185                                     int slots, int slot_width)
 186{
 187        struct snd_soc_component *component = dai->component;
 188        struct hdac_hda_priv *hda_pvt;
 189        struct hdac_hda_pcm *pcm;
 190
 191        hda_pvt = snd_soc_component_get_drvdata(component);
 192        pcm = &hda_pvt->pcm[dai->id];
 193
 194        if (tx_mask)
 195                pcm->stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
 196        else
 197                pcm->stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
 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                        return cpcm;
 368        }
 369
 370        dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name);
 371        return NULL;
 372}
 373
 374static bool is_hdmi_codec(struct hda_codec *hcodec)
 375{
 376        struct hda_pcm *cpcm;
 377
 378        list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) {
 379                if (cpcm->pcm_type == HDA_PCM_TYPE_HDMI)
 380                        return true;
 381        }
 382
 383        return false;
 384}
 385
 386static int hdac_hda_codec_probe(struct snd_soc_component *component)
 387{
 388        struct hdac_hda_priv *hda_pvt =
 389                        snd_soc_component_get_drvdata(component);
 390        struct snd_soc_dapm_context *dapm =
 391                        snd_soc_component_get_dapm(component);
 392        struct hdac_device *hdev = &hda_pvt->codec.core;
 393        struct hda_codec *hcodec = &hda_pvt->codec;
 394        struct hdac_ext_link *hlink;
 395        hda_codec_patch_t patch;
 396        int ret;
 397
 398        hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
 399        if (!hlink) {
 400                dev_err(&hdev->dev, "hdac link not found\n");
 401                return -EIO;
 402        }
 403
 404        snd_hdac_ext_bus_link_get(hdev->bus, hlink);
 405
 406        /*
 407         * Ensure any HDA display is powered at codec probe.
 408         * After snd_hda_codec_device_new(), display power is
 409         * managed by runtime PM.
 410         */
 411        if (hda_pvt->need_display_power)
 412                snd_hdac_display_power(hdev->bus,
 413                                       HDA_CODEC_IDX_CONTROLLER, true);
 414
 415        ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card,
 416                                       hdev->addr, hcodec);
 417        if (ret < 0) {
 418                dev_err(&hdev->dev, "failed to create hda codec %d\n", ret);
 419                goto error_no_pm;
 420        }
 421        /*
 422         * Overwrite type to HDA_DEV_ASOC since it is a ASoC driver
 423         * hda_codec.c will check this flag to determine if unregister
 424         * device is needed.
 425         */
 426        hdev->type = HDA_DEV_ASOC;
 427
 428        /*
 429         * snd_hda_codec_device_new decrements the usage count so call get pm
 430         * else the device will be powered off
 431         */
 432        pm_runtime_get_noresume(&hdev->dev);
 433
 434        hcodec->bus->card = dapm->card->snd_card;
 435
 436        ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name);
 437        if (ret < 0) {
 438                dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name);
 439                goto error_pm;
 440        }
 441
 442        ret = snd_hdac_regmap_init(&hcodec->core);
 443        if (ret < 0) {
 444                dev_err(&hdev->dev, "regmap init failed\n");
 445                goto error_pm;
 446        }
 447
 448        patch = (hda_codec_patch_t)hcodec->preset->driver_data;
 449        if (patch) {
 450                ret = patch(hcodec);
 451                if (ret < 0) {
 452                        dev_err(&hdev->dev, "patch failed %d\n", ret);
 453                        goto error_regmap;
 454                }
 455        } else {
 456                dev_dbg(&hdev->dev, "no patch file found\n");
 457        }
 458
 459        /* configure codec for 1:1 PCM:DAI mapping */
 460        hcodec->mst_no_extra_pcms = 1;
 461
 462        ret = snd_hda_codec_parse_pcms(hcodec);
 463        if (ret < 0) {
 464                dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
 465                goto error_patch;
 466        }
 467
 468        /* HDMI controls need to be created in machine drivers */
 469        if (!is_hdmi_codec(hcodec)) {
 470                ret = snd_hda_codec_build_controls(hcodec);
 471                if (ret < 0) {
 472                        dev_err(&hdev->dev, "unable to create controls %d\n",
 473                                ret);
 474                        goto error_patch;
 475                }
 476        }
 477
 478        hcodec->core.lazy_cache = true;
 479
 480        if (hda_pvt->need_display_power)
 481                snd_hdac_display_power(hdev->bus,
 482                                       HDA_CODEC_IDX_CONTROLLER, false);
 483
 484        /* match for forbid call in snd_hda_codec_device_new() */
 485        pm_runtime_allow(&hdev->dev);
 486
 487        /*
 488         * hdac_device core already sets the state to active and calls
 489         * get_noresume. So enable runtime and set the device to suspend.
 490         * pm_runtime_enable is also called during codec registeration
 491         */
 492        pm_runtime_put(&hdev->dev);
 493        pm_runtime_suspend(&hdev->dev);
 494
 495        return 0;
 496
 497error_patch:
 498        if (hcodec->patch_ops.free)
 499                hcodec->patch_ops.free(hcodec);
 500error_regmap:
 501        snd_hdac_regmap_exit(hdev);
 502error_pm:
 503        pm_runtime_put(&hdev->dev);
 504error_no_pm:
 505        snd_hdac_ext_bus_link_put(hdev->bus, hlink);
 506        return ret;
 507}
 508
 509static void hdac_hda_codec_remove(struct snd_soc_component *component)
 510{
 511        struct hdac_hda_priv *hda_pvt =
 512                      snd_soc_component_get_drvdata(component);
 513        struct hdac_device *hdev = &hda_pvt->codec.core;
 514        struct hda_codec *codec = &hda_pvt->codec;
 515        struct hdac_ext_link *hlink = NULL;
 516
 517        hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
 518        if (!hlink) {
 519                dev_err(&hdev->dev, "hdac link not found\n");
 520                return;
 521        }
 522
 523        pm_runtime_disable(&hdev->dev);
 524        snd_hdac_ext_bus_link_put(hdev->bus, hlink);
 525
 526        if (codec->patch_ops.free)
 527                codec->patch_ops.free(codec);
 528
 529        snd_hda_codec_cleanup_for_unbind(codec);
 530}
 531
 532static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = {
 533        {"AIF1TX", NULL, "Codec Input Pin1"},
 534        {"AIF2TX", NULL, "Codec Input Pin2"},
 535        {"AIF3TX", NULL, "Codec Input Pin3"},
 536
 537        {"Codec Output Pin1", NULL, "AIF1RX"},
 538        {"Codec Output Pin2", NULL, "AIF2RX"},
 539        {"Codec Output Pin3", NULL, "AIF3RX"},
 540};
 541
 542static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = {
 543        /* Audio Interface */
 544        SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0,
 545                            SND_SOC_NOPM, 0, 0),
 546        SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0,
 547                            SND_SOC_NOPM, 0, 0),
 548        SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0,
 549                            SND_SOC_NOPM, 0, 0),
 550        SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0,
 551                             SND_SOC_NOPM, 0, 0),
 552        SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0,
 553                             SND_SOC_NOPM, 0, 0),
 554        SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0,
 555                             SND_SOC_NOPM, 0, 0),
 556
 557        /* Input Pins */
 558        SND_SOC_DAPM_INPUT("Codec Input Pin1"),
 559        SND_SOC_DAPM_INPUT("Codec Input Pin2"),
 560        SND_SOC_DAPM_INPUT("Codec Input Pin3"),
 561
 562        /* Output Pins */
 563        SND_SOC_DAPM_OUTPUT("Codec Output Pin1"),
 564        SND_SOC_DAPM_OUTPUT("Codec Output Pin2"),
 565        SND_SOC_DAPM_OUTPUT("Codec Output Pin3"),
 566};
 567
 568static const struct snd_soc_component_driver hdac_hda_codec = {
 569        .probe          = hdac_hda_codec_probe,
 570        .remove         = hdac_hda_codec_remove,
 571        .idle_bias_on   = false,
 572        .dapm_widgets           = hdac_hda_dapm_widgets,
 573        .num_dapm_widgets       = ARRAY_SIZE(hdac_hda_dapm_widgets),
 574        .dapm_routes            = hdac_hda_dapm_routes,
 575        .num_dapm_routes        = ARRAY_SIZE(hdac_hda_dapm_routes),
 576};
 577
 578static int hdac_hda_dev_probe(struct hdac_device *hdev)
 579{
 580        struct hdac_ext_link *hlink;
 581        struct hdac_hda_priv *hda_pvt;
 582        int ret;
 583
 584        /* hold the ref while we probe */
 585        hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
 586        if (!hlink) {
 587                dev_err(&hdev->dev, "hdac link not found\n");
 588                return -EIO;
 589        }
 590        snd_hdac_ext_bus_link_get(hdev->bus, hlink);
 591
 592        hda_pvt = hdac_to_hda_priv(hdev);
 593        if (!hda_pvt)
 594                return -ENOMEM;
 595
 596        /* ASoC specific initialization */
 597        ret = devm_snd_soc_register_component(&hdev->dev,
 598                                         &hdac_hda_codec, hdac_hda_dais,
 599                                         ARRAY_SIZE(hdac_hda_dais));
 600        if (ret < 0) {
 601                dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret);
 602                return ret;
 603        }
 604
 605        dev_set_drvdata(&hdev->dev, hda_pvt);
 606        snd_hdac_ext_bus_link_put(hdev->bus, hlink);
 607
 608        return ret;
 609}
 610
 611static int hdac_hda_dev_remove(struct hdac_device *hdev)
 612{
 613        /*
 614         * Resources are freed in hdac_hda_codec_remove(). This
 615         * function is kept to keep hda_codec_driver_remove() happy.
 616         */
 617        return 0;
 618}
 619
 620static struct hdac_ext_bus_ops hdac_ops = {
 621        .hdev_attach = hdac_hda_dev_probe,
 622        .hdev_detach = hdac_hda_dev_remove,
 623};
 624
 625struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void)
 626{
 627        return &hdac_ops;
 628}
 629EXPORT_SYMBOL_GPL(snd_soc_hdac_hda_get_ops);
 630
 631MODULE_LICENSE("GPL v2");
 632MODULE_DESCRIPTION("ASoC Extensions for legacy HDA Drivers");
 633MODULE_AUTHOR("Rakesh Ughreja<rakesh.a.ughreja@intel.com>");
 634