linux/sound/soc/intel/boards/sof_nau8825.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2// Copyright(c) 2021 Intel Corporation.
   3// Copyright(c) 2021 Nuvoton Corporation.
   4
   5/*
   6 * Intel SOF Machine Driver with Nuvoton headphone codec NAU8825
   7 * and speaker codec RT1019P MAX98360a or MAX98373
   8 */
   9#include <linux/i2c.h>
  10#include <linux/input.h>
  11#include <linux/module.h>
  12#include <linux/platform_device.h>
  13#include <linux/dmi.h>
  14#include <sound/core.h>
  15#include <sound/jack.h>
  16#include <sound/pcm.h>
  17#include <sound/pcm_params.h>
  18#include <sound/soc.h>
  19#include <sound/sof.h>
  20#include <sound/soc-acpi.h>
  21#include "../../codecs/nau8825.h"
  22#include "../common/soc-intel-quirks.h"
  23#include "hda_dsp_common.h"
  24#include "sof_realtek_common.h"
  25#include "sof_maxim_common.h"
  26
  27#define NAME_SIZE 32
  28
  29#define SOF_NAU8825_SSP_CODEC(quirk)            ((quirk) & GENMASK(2, 0))
  30#define SOF_NAU8825_SSP_CODEC_MASK              (GENMASK(2, 0))
  31#define SOF_SPEAKER_AMP_PRESENT         BIT(3)
  32#define SOF_NAU8825_SSP_AMP_SHIFT               4
  33#define SOF_NAU8825_SSP_AMP_MASK                (GENMASK(6, 4))
  34#define SOF_NAU8825_SSP_AMP(quirk)      \
  35        (((quirk) << SOF_NAU8825_SSP_AMP_SHIFT) & SOF_NAU8825_SSP_AMP_MASK)
  36#define SOF_NAU8825_NUM_HDMIDEV_SHIFT           7
  37#define SOF_NAU8825_NUM_HDMIDEV_MASK            (GENMASK(9, 7))
  38#define SOF_NAU8825_NUM_HDMIDEV(quirk)  \
  39        (((quirk) << SOF_NAU8825_NUM_HDMIDEV_SHIFT) & SOF_NAU8825_NUM_HDMIDEV_MASK)
  40
  41/* BT audio offload: reserve 3 bits for future */
  42#define SOF_BT_OFFLOAD_SSP_SHIFT                10
  43#define SOF_BT_OFFLOAD_SSP_MASK         (GENMASK(12, 10))
  44#define SOF_BT_OFFLOAD_SSP(quirk)       \
  45        (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
  46#define SOF_SSP_BT_OFFLOAD_PRESENT              BIT(13)
  47#define SOF_RT1019P_SPEAKER_AMP_PRESENT BIT(14)
  48#define SOF_MAX98373_SPEAKER_AMP_PRESENT        BIT(15)
  49#define SOF_MAX98360A_SPEAKER_AMP_PRESENT       BIT(16)
  50
  51static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
  52
  53struct sof_hdmi_pcm {
  54        struct list_head head;
  55        struct snd_soc_dai *codec_dai;
  56        int device;
  57};
  58
  59struct sof_card_private {
  60        struct clk *mclk;
  61        struct snd_soc_jack sof_headset;
  62        struct list_head hdmi_pcm_list;
  63};
  64
  65static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
  66{
  67        struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
  68        struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
  69        struct sof_hdmi_pcm *pcm;
  70
  71        pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
  72        if (!pcm)
  73                return -ENOMEM;
  74
  75        /* dai_link id is 1:1 mapped to the PCM device */
  76        pcm->device = rtd->dai_link->id;
  77        pcm->codec_dai = dai;
  78
  79        list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
  80
  81        return 0;
  82}
  83
  84static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
  85{
  86        struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
  87        struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
  88
  89        struct snd_soc_jack *jack;
  90        int ret;
  91
  92        /*
  93         * Headset buttons map to the google Reference headset.
  94         * These can be configured by userspace.
  95         */
  96        ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
  97                                    SND_JACK_HEADSET | SND_JACK_BTN_0 |
  98                                    SND_JACK_BTN_1 | SND_JACK_BTN_2 |
  99                                    SND_JACK_BTN_3,
 100                                    &ctx->sof_headset, NULL, 0);
 101        if (ret) {
 102                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
 103                return ret;
 104        }
 105
 106        jack = &ctx->sof_headset;
 107
 108        snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
 109        snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
 110        snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
 111        snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 112        ret = snd_soc_component_set_jack(component, jack, NULL);
 113
 114        if (ret) {
 115                dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
 116                return ret;
 117        }
 118
 119        return ret;
 120};
 121
 122static void sof_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd)
 123{
 124        struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
 125
 126        snd_soc_component_set_jack(component, NULL, NULL);
 127}
 128
 129static int sof_nau8825_hw_params(struct snd_pcm_substream *substream,
 130                                 struct snd_pcm_hw_params *params)
 131{
 132        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 133        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 134        int clk_freq, ret;
 135
 136        clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */
 137
 138        if (clk_freq <= 0) {
 139                dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq);
 140                return -EINVAL;
 141        }
 142
 143        /* Configure clock for codec */
 144        ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0,
 145                                     SND_SOC_CLOCK_IN);
 146        if (ret < 0) {
 147                dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret);
 148                return ret;
 149        }
 150
 151        /* Configure pll for codec */
 152        ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq,
 153                                  params_rate(params) * 256);
 154        if (ret < 0) {
 155                dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret);
 156                return ret;
 157        }
 158
 159        return ret;
 160}
 161
 162static struct snd_soc_ops sof_nau8825_ops = {
 163        .hw_params = sof_nau8825_hw_params,
 164};
 165
 166static struct snd_soc_dai_link_component platform_component[] = {
 167        {
 168                /* name might be overridden during probe */
 169                .name = "0000:00:1f.3"
 170        }
 171};
 172
 173static int sof_card_late_probe(struct snd_soc_card *card)
 174{
 175        struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
 176        struct snd_soc_dapm_context *dapm = &card->dapm;
 177        struct sof_hdmi_pcm *pcm;
 178        int err;
 179
 180        if (list_empty(&ctx->hdmi_pcm_list))
 181                return -EINVAL;
 182
 183        pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
 184
 185        if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
 186                /* Disable Left and Right Spk pin after boot */
 187                snd_soc_dapm_disable_pin(dapm, "Left Spk");
 188                snd_soc_dapm_disable_pin(dapm, "Right Spk");
 189                err = snd_soc_dapm_sync(dapm);
 190                if (err < 0)
 191                        return err;
 192        }
 193
 194        return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
 195}
 196
 197static const struct snd_kcontrol_new sof_controls[] = {
 198        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
 199        SOC_DAPM_PIN_SWITCH("Headset Mic"),
 200        SOC_DAPM_PIN_SWITCH("Left Spk"),
 201        SOC_DAPM_PIN_SWITCH("Right Spk"),
 202};
 203
 204static const struct snd_kcontrol_new speaker_controls[] = {
 205        SOC_DAPM_PIN_SWITCH("Spk"),
 206};
 207
 208static const struct snd_soc_dapm_widget sof_widgets[] = {
 209        SND_SOC_DAPM_HP("Headphone Jack", NULL),
 210        SND_SOC_DAPM_MIC("Headset Mic", NULL),
 211        SND_SOC_DAPM_SPK("Left Spk", NULL),
 212        SND_SOC_DAPM_SPK("Right Spk", NULL),
 213};
 214
 215static const struct snd_soc_dapm_widget speaker_widgets[] = {
 216        SND_SOC_DAPM_SPK("Spk", NULL),
 217};
 218
 219static const struct snd_soc_dapm_widget dmic_widgets[] = {
 220        SND_SOC_DAPM_MIC("SoC DMIC", NULL),
 221};
 222
 223static const struct snd_soc_dapm_route sof_map[] = {
 224        /* HP jack connectors - unknown if we have jack detection */
 225        { "Headphone Jack", NULL, "HPOL" },
 226        { "Headphone Jack", NULL, "HPOR" },
 227
 228        /* other jacks */
 229        { "MIC", NULL, "Headset Mic" },
 230};
 231
 232static const struct snd_soc_dapm_route speaker_map[] = {
 233        /* speaker */
 234        { "Spk", NULL, "Speaker" },
 235};
 236
 237static const struct snd_soc_dapm_route dmic_map[] = {
 238        /* digital mics */
 239        {"DMic", NULL, "SoC DMIC"},
 240};
 241
 242static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd)
 243{
 244        struct snd_soc_card *card = rtd->card;
 245        int ret;
 246
 247        ret = snd_soc_dapm_new_controls(&card->dapm, speaker_widgets,
 248                                        ARRAY_SIZE(speaker_widgets));
 249        if (ret) {
 250                dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret);
 251                /* Don't need to add routes if widget addition failed */
 252                return ret;
 253        }
 254
 255        ret = snd_soc_add_card_controls(card, speaker_controls,
 256                                        ARRAY_SIZE(speaker_controls));
 257        if (ret) {
 258                dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
 259                return ret;
 260        }
 261
 262        ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map,
 263                                      ARRAY_SIZE(speaker_map));
 264
 265        if (ret)
 266                dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
 267        return ret;
 268}
 269
 270static int dmic_init(struct snd_soc_pcm_runtime *rtd)
 271{
 272        struct snd_soc_card *card = rtd->card;
 273        int ret;
 274
 275        ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
 276                                        ARRAY_SIZE(dmic_widgets));
 277        if (ret) {
 278                dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
 279                /* Don't need to add routes if widget addition failed */
 280                return ret;
 281        }
 282
 283        ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
 284                                      ARRAY_SIZE(dmic_map));
 285
 286        if (ret)
 287                dev_err(card->dev, "DMic map addition failed: %d\n", ret);
 288
 289        return ret;
 290}
 291
 292/* sof audio machine driver for nau8825 codec */
 293static struct snd_soc_card sof_audio_card_nau8825 = {
 294        .name = "nau8825", /* the sof- prefix is added by the core */
 295        .owner = THIS_MODULE,
 296        .controls = sof_controls,
 297        .num_controls = ARRAY_SIZE(sof_controls),
 298        .dapm_widgets = sof_widgets,
 299        .num_dapm_widgets = ARRAY_SIZE(sof_widgets),
 300        .dapm_routes = sof_map,
 301        .num_dapm_routes = ARRAY_SIZE(sof_map),
 302        .fully_routed = true,
 303        .late_probe = sof_card_late_probe,
 304};
 305
 306static struct snd_soc_dai_link_component nau8825_component[] = {
 307        {
 308                .name = "i2c-10508825:00",
 309                .dai_name = "nau8825-hifi",
 310        }
 311};
 312
 313static struct snd_soc_dai_link_component dmic_component[] = {
 314        {
 315                .name = "dmic-codec",
 316                .dai_name = "dmic-hifi",
 317        }
 318};
 319
 320static struct snd_soc_dai_link_component rt1019p_component[] = {
 321        {
 322                .name = "RTL1019:00",
 323                .dai_name = "HiFi",
 324        }
 325};
 326
 327static struct snd_soc_dai_link_component dummy_component[] = {
 328        {
 329                .name = "snd-soc-dummy",
 330                .dai_name = "snd-soc-dummy-dai",
 331        }
 332};
 333
 334static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
 335                                                          int ssp_codec,
 336                                                          int ssp_amp,
 337                                                          int dmic_be_num,
 338                                                          int hdmi_num)
 339{
 340        struct snd_soc_dai_link_component *idisp_components;
 341        struct snd_soc_dai_link_component *cpus;
 342        struct snd_soc_dai_link *links;
 343        int i, id = 0;
 344
 345        links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
 346                             sof_audio_card_nau8825.num_links, GFP_KERNEL);
 347        cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
 348                             sof_audio_card_nau8825.num_links, GFP_KERNEL);
 349        if (!links || !cpus)
 350                goto devm_err;
 351
 352        /* codec SSP */
 353        links[id].name = devm_kasprintf(dev, GFP_KERNEL,
 354                                        "SSP%d-Codec", ssp_codec);
 355        if (!links[id].name)
 356                goto devm_err;
 357
 358        links[id].id = id;
 359        links[id].codecs = nau8825_component;
 360        links[id].num_codecs = ARRAY_SIZE(nau8825_component);
 361        links[id].platforms = platform_component;
 362        links[id].num_platforms = ARRAY_SIZE(platform_component);
 363        links[id].init = sof_nau8825_codec_init;
 364        links[id].exit = sof_nau8825_codec_exit;
 365        links[id].ops = &sof_nau8825_ops;
 366        links[id].dpcm_playback = 1;
 367        links[id].dpcm_capture = 1;
 368        links[id].no_pcm = 1;
 369        links[id].cpus = &cpus[id];
 370        links[id].num_cpus = 1;
 371
 372        links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
 373                                                  "SSP%d Pin",
 374                                                  ssp_codec);
 375        if (!links[id].cpus->dai_name)
 376                goto devm_err;
 377
 378        id++;
 379
 380        /* dmic */
 381        if (dmic_be_num > 0) {
 382                /* at least we have dmic01 */
 383                links[id].name = "dmic01";
 384                links[id].cpus = &cpus[id];
 385                links[id].cpus->dai_name = "DMIC01 Pin";
 386                links[id].init = dmic_init;
 387                if (dmic_be_num > 1) {
 388                        /* set up 2 BE links at most */
 389                        links[id + 1].name = "dmic16k";
 390                        links[id + 1].cpus = &cpus[id + 1];
 391                        links[id + 1].cpus->dai_name = "DMIC16k Pin";
 392                        dmic_be_num = 2;
 393                }
 394        }
 395
 396        for (i = 0; i < dmic_be_num; i++) {
 397                links[id].id = id;
 398                links[id].num_cpus = 1;
 399                links[id].codecs = dmic_component;
 400                links[id].num_codecs = ARRAY_SIZE(dmic_component);
 401                links[id].platforms = platform_component;
 402                links[id].num_platforms = ARRAY_SIZE(platform_component);
 403                links[id].ignore_suspend = 1;
 404                links[id].dpcm_capture = 1;
 405                links[id].no_pcm = 1;
 406                id++;
 407        }
 408
 409        /* HDMI */
 410        if (hdmi_num > 0) {
 411                idisp_components = devm_kzalloc(dev,
 412                                                sizeof(struct snd_soc_dai_link_component) *
 413                                                hdmi_num, GFP_KERNEL);
 414                if (!idisp_components)
 415                        goto devm_err;
 416        }
 417        for (i = 1; i <= hdmi_num; i++) {
 418                links[id].name = devm_kasprintf(dev, GFP_KERNEL,
 419                                                "iDisp%d", i);
 420                if (!links[id].name)
 421                        goto devm_err;
 422
 423                links[id].id = id;
 424                links[id].cpus = &cpus[id];
 425                links[id].num_cpus = 1;
 426                links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
 427                                                          "iDisp%d Pin", i);
 428                if (!links[id].cpus->dai_name)
 429                        goto devm_err;
 430
 431                idisp_components[i - 1].name = "ehdaudio0D2";
 432                idisp_components[i - 1].dai_name = devm_kasprintf(dev,
 433                                                                  GFP_KERNEL,
 434                                                                  "intel-hdmi-hifi%d",
 435                                                                  i);
 436                if (!idisp_components[i - 1].dai_name)
 437                        goto devm_err;
 438
 439                links[id].codecs = &idisp_components[i - 1];
 440                links[id].num_codecs = 1;
 441                links[id].platforms = platform_component;
 442                links[id].num_platforms = ARRAY_SIZE(platform_component);
 443                links[id].init = sof_hdmi_init;
 444                links[id].dpcm_playback = 1;
 445                links[id].no_pcm = 1;
 446                id++;
 447        }
 448
 449        /* speaker amp */
 450        if (sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT) {
 451                links[id].name = devm_kasprintf(dev, GFP_KERNEL,
 452                                                "SSP%d-Codec", ssp_amp);
 453                if (!links[id].name)
 454                        goto devm_err;
 455
 456                links[id].id = id;
 457                if (sof_nau8825_quirk & SOF_RT1019P_SPEAKER_AMP_PRESENT) {
 458                        links[id].codecs = rt1019p_component;
 459                        links[id].num_codecs = ARRAY_SIZE(rt1019p_component);
 460                        links[id].init = speaker_codec_init;
 461                } else if (sof_nau8825_quirk &
 462                                SOF_MAX98373_SPEAKER_AMP_PRESENT) {
 463                        links[id].codecs = max_98373_components;
 464                        links[id].num_codecs = ARRAY_SIZE(max_98373_components);
 465                        links[id].init = max_98373_spk_codec_init;
 466                        links[id].ops = &max_98373_ops;
 467                        /* feedback stream */
 468                        links[id].dpcm_capture = 1;
 469                } else if (sof_nau8825_quirk &
 470                                SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
 471                        max_98360a_dai_link(&links[id]);
 472                } else {
 473                        goto devm_err;
 474                }
 475
 476                links[id].platforms = platform_component;
 477                links[id].num_platforms = ARRAY_SIZE(platform_component);
 478                links[id].dpcm_playback = 1;
 479                links[id].no_pcm = 1;
 480                links[id].cpus = &cpus[id];
 481                links[id].num_cpus = 1;
 482                links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
 483                                                          "SSP%d Pin",
 484                                                          ssp_amp);
 485                if (!links[id].cpus->dai_name)
 486                        goto devm_err;
 487                id++;
 488        }
 489
 490        /* BT audio offload */
 491        if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
 492                int port = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
 493                                SOF_BT_OFFLOAD_SSP_SHIFT;
 494
 495                links[id].id = id;
 496                links[id].cpus = &cpus[id];
 497                links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
 498                                                          "SSP%d Pin", port);
 499                if (!links[id].cpus->dai_name)
 500                        goto devm_err;
 501                links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
 502                if (!links[id].name)
 503                        goto devm_err;
 504                links[id].codecs = dummy_component;
 505                links[id].num_codecs = ARRAY_SIZE(dummy_component);
 506                links[id].platforms = platform_component;
 507                links[id].num_platforms = ARRAY_SIZE(platform_component);
 508                links[id].dpcm_playback = 1;
 509                links[id].dpcm_capture = 1;
 510                links[id].no_pcm = 1;
 511                links[id].num_cpus = 1;
 512        }
 513
 514        return links;
 515devm_err:
 516        return NULL;
 517}
 518
 519static int sof_audio_probe(struct platform_device *pdev)
 520{
 521        struct snd_soc_dai_link *dai_links;
 522        struct snd_soc_acpi_mach *mach;
 523        struct sof_card_private *ctx;
 524        int dmic_be_num, hdmi_num;
 525        int ret, ssp_amp, ssp_codec;
 526
 527        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 528        if (!ctx)
 529                return -ENOMEM;
 530
 531        if (pdev->id_entry && pdev->id_entry->driver_data)
 532                sof_nau8825_quirk = (unsigned long)pdev->id_entry->driver_data;
 533
 534        mach = pdev->dev.platform_data;
 535
 536        /* A speaker amp might not be present when the quirk claims one is.
 537         * Detect this via whether the machine driver match includes quirk_data.
 538         */
 539        if ((sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT) && !mach->quirk_data)
 540                sof_nau8825_quirk &= ~SOF_SPEAKER_AMP_PRESENT;
 541
 542        dev_dbg(&pdev->dev, "sof_nau8825_quirk = %lx\n", sof_nau8825_quirk);
 543
 544        /* default number of DMIC DAI's */
 545        dmic_be_num = 2;
 546        hdmi_num = (sof_nau8825_quirk & SOF_NAU8825_NUM_HDMIDEV_MASK) >>
 547                        SOF_NAU8825_NUM_HDMIDEV_SHIFT;
 548        /* default number of HDMI DAI's */
 549        if (!hdmi_num)
 550                hdmi_num = 3;
 551
 552        ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >>
 553                        SOF_NAU8825_SSP_AMP_SHIFT;
 554
 555        ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK;
 556
 557        /* compute number of dai links */
 558        sof_audio_card_nau8825.num_links = 1 + dmic_be_num + hdmi_num;
 559
 560        if (sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT)
 561                sof_audio_card_nau8825.num_links++;
 562
 563        if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
 564                max_98373_set_codec_conf(&sof_audio_card_nau8825);
 565
 566        if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
 567                sof_audio_card_nau8825.num_links++;
 568
 569        dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
 570                                              dmic_be_num, hdmi_num);
 571        if (!dai_links)
 572                return -ENOMEM;
 573
 574        sof_audio_card_nau8825.dai_link = dai_links;
 575
 576        INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 577
 578        sof_audio_card_nau8825.dev = &pdev->dev;
 579
 580        /* set platform name for each dailink */
 581        ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_nau8825,
 582                                                    mach->mach_params.platform);
 583        if (ret)
 584                return ret;
 585
 586        snd_soc_card_set_drvdata(&sof_audio_card_nau8825, ctx);
 587
 588        return devm_snd_soc_register_card(&pdev->dev,
 589                                          &sof_audio_card_nau8825);
 590}
 591
 592static const struct platform_device_id board_ids[] = {
 593        {
 594                .name = "sof_nau8825",
 595                .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
 596                                        SOF_NAU8825_NUM_HDMIDEV(4) |
 597                                        SOF_BT_OFFLOAD_SSP(2) |
 598                                        SOF_SSP_BT_OFFLOAD_PRESENT),
 599
 600        },
 601        {
 602                .name = "adl_rt1019p_nau8825",
 603                .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
 604                                        SOF_SPEAKER_AMP_PRESENT |
 605                                        SOF_RT1019P_SPEAKER_AMP_PRESENT |
 606                                        SOF_NAU8825_SSP_AMP(2) |
 607                                        SOF_NAU8825_NUM_HDMIDEV(4)),
 608        },
 609        {
 610                .name = "adl_max98373_nau8825",
 611                .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
 612                                        SOF_SPEAKER_AMP_PRESENT |
 613                                        SOF_MAX98373_SPEAKER_AMP_PRESENT |
 614                                        SOF_NAU8825_SSP_AMP(1) |
 615                                        SOF_NAU8825_NUM_HDMIDEV(4) |
 616                                        SOF_BT_OFFLOAD_SSP(2) |
 617                                        SOF_SSP_BT_OFFLOAD_PRESENT),
 618        },
 619        {
 620                /* The limitation of length of char array, shorten the name */
 621                .name = "adl_mx98360a_nau8825",
 622                .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
 623                                        SOF_SPEAKER_AMP_PRESENT |
 624                                        SOF_MAX98360A_SPEAKER_AMP_PRESENT |
 625                                        SOF_NAU8825_SSP_AMP(1) |
 626                                        SOF_NAU8825_NUM_HDMIDEV(4) |
 627                                        SOF_BT_OFFLOAD_SSP(2) |
 628                                        SOF_SSP_BT_OFFLOAD_PRESENT),
 629
 630        },
 631        { }
 632};
 633MODULE_DEVICE_TABLE(platform, board_ids);
 634
 635static struct platform_driver sof_audio = {
 636        .probe = sof_audio_probe,
 637        .driver = {
 638                .name = "sof_nau8825",
 639                .pm = &snd_soc_pm_ops,
 640        },
 641        .id_table = board_ids,
 642};
 643module_platform_driver(sof_audio)
 644
 645/* Module information */
 646MODULE_DESCRIPTION("SOF Audio Machine driver for NAU8825");
 647MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>");
 648MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
 649MODULE_LICENSE("GPL");
 650MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
 651MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
 652