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