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