Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright(c) 2021 Intel Corporation.
0003 
0004 /*
0005  * Intel SOF Machine Driver with Cirrus Logic CS42L42 Codec
0006  * and speaker codec MAX98357A
0007  */
0008 #include <linux/i2c.h>
0009 #include <linux/input.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/regulator/consumer.h>
0013 #include <linux/dmi.h>
0014 #include <sound/core.h>
0015 #include <sound/jack.h>
0016 #include <sound/pcm.h>
0017 #include <sound/pcm_params.h>
0018 #include <sound/soc.h>
0019 #include <sound/sof.h>
0020 #include <sound/soc-acpi.h>
0021 #include <dt-bindings/sound/cs42l42.h>
0022 #include "../../codecs/hdac_hdmi.h"
0023 #include "../common/soc-intel-quirks.h"
0024 #include "hda_dsp_common.h"
0025 #include "sof_maxim_common.h"
0026 
0027 #define NAME_SIZE 32
0028 
0029 #define SOF_CS42L42_SSP_CODEC(quirk)        ((quirk) & GENMASK(2, 0))
0030 #define SOF_CS42L42_SSP_CODEC_MASK      (GENMASK(2, 0))
0031 #define SOF_SPEAKER_AMP_PRESENT         BIT(3)
0032 #define SOF_CS42L42_SSP_AMP_SHIFT       4
0033 #define SOF_CS42L42_SSP_AMP_MASK        (GENMASK(6, 4))
0034 #define SOF_CS42L42_SSP_AMP(quirk)  \
0035     (((quirk) << SOF_CS42L42_SSP_AMP_SHIFT) & SOF_CS42L42_SSP_AMP_MASK)
0036 #define SOF_CS42L42_NUM_HDMIDEV_SHIFT       7
0037 #define SOF_CS42L42_NUM_HDMIDEV_MASK        (GENMASK(9, 7))
0038 #define SOF_CS42L42_NUM_HDMIDEV(quirk)  \
0039     (((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK)
0040 #define SOF_CS42L42_DAILINK_SHIFT       10
0041 #define SOF_CS42L42_DAILINK_MASK        (GENMASK(24, 10))
0042 #define SOF_CS42L42_DAILINK(link1, link2, link3, link4, link5) \
0043     ((((link1) | ((link2) << 3) | ((link3) << 6) | ((link4) << 9) | ((link5) << 12)) << SOF_CS42L42_DAILINK_SHIFT) & SOF_CS42L42_DAILINK_MASK)
0044 #define SOF_BT_OFFLOAD_PRESENT          BIT(25)
0045 #define SOF_CS42L42_SSP_BT_SHIFT        26
0046 #define SOF_CS42L42_SSP_BT_MASK         (GENMASK(28, 26))
0047 #define SOF_CS42L42_SSP_BT(quirk)   \
0048     (((quirk) << SOF_CS42L42_SSP_BT_SHIFT) & SOF_CS42L42_SSP_BT_MASK)
0049 #define SOF_MAX98357A_SPEAKER_AMP_PRESENT   BIT(29)
0050 #define SOF_MAX98360A_SPEAKER_AMP_PRESENT   BIT(30)
0051 
0052 enum {
0053     LINK_NONE = 0,
0054     LINK_HP = 1,
0055     LINK_SPK = 2,
0056     LINK_DMIC = 3,
0057     LINK_HDMI = 4,
0058     LINK_BT = 5,
0059 };
0060 
0061 static struct snd_soc_jack_pin jack_pins[] = {
0062     {
0063         .pin    = "Headphone Jack",
0064         .mask   = SND_JACK_HEADPHONE,
0065     },
0066     {
0067         .pin    = "Headset Mic",
0068         .mask   = SND_JACK_MICROPHONE,
0069     },
0070 };
0071 
0072 /* Default: SSP2 */
0073 static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2);
0074 
0075 struct sof_hdmi_pcm {
0076     struct list_head head;
0077     struct snd_soc_dai *codec_dai;
0078     struct snd_soc_jack hdmi_jack;
0079     int device;
0080 };
0081 
0082 struct sof_card_private {
0083     struct snd_soc_jack headset_jack;
0084     struct list_head hdmi_pcm_list;
0085     bool common_hdmi_codec_drv;
0086 };
0087 
0088 static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
0089 {
0090     struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
0091     struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
0092     struct sof_hdmi_pcm *pcm;
0093 
0094     pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
0095     if (!pcm)
0096         return -ENOMEM;
0097 
0098     /* dai_link id is 1:1 mapped to the PCM device */
0099     pcm->device = rtd->dai_link->id;
0100     pcm->codec_dai = dai;
0101 
0102     list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
0103 
0104     return 0;
0105 }
0106 
0107 static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
0108 {
0109     struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
0110     struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
0111     struct snd_soc_jack *jack = &ctx->headset_jack;
0112     int ret;
0113 
0114     /*
0115      * Headset buttons map to the google Reference headset.
0116      * These can be configured by userspace.
0117      */
0118     ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
0119                      SND_JACK_HEADSET | SND_JACK_BTN_0 |
0120                      SND_JACK_BTN_1 | SND_JACK_BTN_2 |
0121                      SND_JACK_BTN_3,
0122                      jack,
0123                      jack_pins,
0124                      ARRAY_SIZE(jack_pins));
0125     if (ret) {
0126         dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
0127         return ret;
0128     }
0129 
0130     snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
0131     snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
0132     snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
0133     snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
0134 
0135     ret = snd_soc_component_set_jack(component, jack, NULL);
0136     if (ret) {
0137         dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
0138         return ret;
0139     }
0140 
0141     return ret;
0142 };
0143 
0144 static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd)
0145 {
0146     struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
0147 
0148     snd_soc_component_set_jack(component, NULL, NULL);
0149 }
0150 
0151 static int sof_cs42l42_hw_params(struct snd_pcm_substream *substream,
0152                  struct snd_pcm_hw_params *params)
0153 {
0154     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0155     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0156     int clk_freq, ret;
0157 
0158     clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */
0159 
0160     if (clk_freq <= 0) {
0161         dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq);
0162         return -EINVAL;
0163     }
0164 
0165     /* Configure sysclk for codec */
0166     ret = snd_soc_dai_set_sysclk(codec_dai, 0,
0167                      clk_freq, SND_SOC_CLOCK_IN);
0168     if (ret < 0)
0169         dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
0170 
0171     return ret;
0172 }
0173 
0174 static const struct snd_soc_ops sof_cs42l42_ops = {
0175     .hw_params = sof_cs42l42_hw_params,
0176 };
0177 
0178 static struct snd_soc_dai_link_component platform_component[] = {
0179     {
0180         /* name might be overridden during probe */
0181         .name = "0000:00:1f.3"
0182     }
0183 };
0184 
0185 static int sof_card_late_probe(struct snd_soc_card *card)
0186 {
0187     struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
0188     struct snd_soc_component *component = NULL;
0189     char jack_name[NAME_SIZE];
0190     struct sof_hdmi_pcm *pcm;
0191     int err;
0192 
0193     if (list_empty(&ctx->hdmi_pcm_list))
0194         return -EINVAL;
0195 
0196     if (ctx->common_hdmi_codec_drv) {
0197         pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
0198                        head);
0199         component = pcm->codec_dai->component;
0200         return hda_dsp_hdmi_build_controls(card, component);
0201     }
0202 
0203     list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
0204         component = pcm->codec_dai->component;
0205         snprintf(jack_name, sizeof(jack_name),
0206              "HDMI/DP, pcm=%d Jack", pcm->device);
0207         err = snd_soc_card_jack_new(card, jack_name,
0208                         SND_JACK_AVOUT, &pcm->hdmi_jack);
0209 
0210         if (err)
0211             return err;
0212 
0213         err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
0214                       &pcm->hdmi_jack);
0215         if (err < 0)
0216             return err;
0217     }
0218 
0219     return hdac_hdmi_jack_port_init(component, &card->dapm);
0220 }
0221 
0222 static const struct snd_kcontrol_new sof_controls[] = {
0223     SOC_DAPM_PIN_SWITCH("Headphone Jack"),
0224     SOC_DAPM_PIN_SWITCH("Headset Mic"),
0225 };
0226 
0227 static const struct snd_soc_dapm_widget sof_widgets[] = {
0228     SND_SOC_DAPM_HP("Headphone Jack", NULL),
0229     SND_SOC_DAPM_MIC("Headset Mic", NULL),
0230 };
0231 
0232 static const struct snd_soc_dapm_widget dmic_widgets[] = {
0233     SND_SOC_DAPM_MIC("SoC DMIC", NULL),
0234 };
0235 
0236 static const struct snd_soc_dapm_route sof_map[] = {
0237     /* HP jack connectors - unknown if we have jack detection */
0238     {"Headphone Jack", NULL, "HP"},
0239 
0240     /* other jacks */
0241     {"HS", NULL, "Headset Mic"},
0242 };
0243 
0244 static const struct snd_soc_dapm_route dmic_map[] = {
0245     /* digital mics */
0246     {"DMic", NULL, "SoC DMIC"},
0247 };
0248 
0249 static int dmic_init(struct snd_soc_pcm_runtime *rtd)
0250 {
0251     struct snd_soc_card *card = rtd->card;
0252     int ret;
0253 
0254     ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
0255                     ARRAY_SIZE(dmic_widgets));
0256     if (ret) {
0257         dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
0258         /* Don't need to add routes if widget addition failed */
0259         return ret;
0260     }
0261 
0262     ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
0263                       ARRAY_SIZE(dmic_map));
0264 
0265     if (ret)
0266         dev_err(card->dev, "DMic map addition failed: %d\n", ret);
0267 
0268     return ret;
0269 }
0270 
0271 /* sof audio machine driver for cs42l42 codec */
0272 static struct snd_soc_card sof_audio_card_cs42l42 = {
0273     .name = "cs42l42", /* the sof- prefix is added by the core */
0274     .owner = THIS_MODULE,
0275     .controls = sof_controls,
0276     .num_controls = ARRAY_SIZE(sof_controls),
0277     .dapm_widgets = sof_widgets,
0278     .num_dapm_widgets = ARRAY_SIZE(sof_widgets),
0279     .dapm_routes = sof_map,
0280     .num_dapm_routes = ARRAY_SIZE(sof_map),
0281     .fully_routed = true,
0282     .late_probe = sof_card_late_probe,
0283 };
0284 
0285 static struct snd_soc_dai_link_component cs42l42_component[] = {
0286     {
0287         .name = "i2c-10134242:00",
0288         .dai_name = "cs42l42",
0289     }
0290 };
0291 
0292 static struct snd_soc_dai_link_component dmic_component[] = {
0293     {
0294         .name = "dmic-codec",
0295         .dai_name = "dmic-hifi",
0296     }
0297 };
0298 
0299 static struct snd_soc_dai_link_component dummy_component[] = {
0300     {
0301         .name = "snd-soc-dummy",
0302         .dai_name = "snd-soc-dummy-dai",
0303     }
0304 };
0305 
0306 static int create_spk_amp_dai_links(struct device *dev,
0307                     struct snd_soc_dai_link *links,
0308                     struct snd_soc_dai_link_component *cpus,
0309                     int *id, int ssp_amp)
0310 {
0311     int ret = 0;
0312 
0313     /* speaker amp */
0314     if (!(sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT))
0315         return 0;
0316 
0317     links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec",
0318                      ssp_amp);
0319     if (!links[*id].name) {
0320         ret = -ENOMEM;
0321         goto devm_err;
0322     }
0323 
0324     links[*id].id = *id;
0325 
0326     if (sof_cs42l42_quirk & SOF_MAX98357A_SPEAKER_AMP_PRESENT) {
0327         max_98357a_dai_link(&links[*id]);
0328     } else if (sof_cs42l42_quirk & SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
0329         max_98360a_dai_link(&links[*id]);
0330     } else {
0331         dev_err(dev, "no amp defined\n");
0332         ret = -EINVAL;
0333         goto devm_err;
0334     }
0335 
0336     links[*id].platforms = platform_component;
0337     links[*id].num_platforms = ARRAY_SIZE(platform_component);
0338     links[*id].dpcm_playback = 1;
0339     links[*id].no_pcm = 1;
0340     links[*id].cpus = &cpus[*id];
0341     links[*id].num_cpus = 1;
0342 
0343     links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
0344                            "SSP%d Pin", ssp_amp);
0345     if (!links[*id].cpus->dai_name) {
0346         ret = -ENOMEM;
0347         goto devm_err;
0348     }
0349 
0350     (*id)++;
0351 
0352 devm_err:
0353     return ret;
0354 }
0355 
0356 static int create_hp_codec_dai_links(struct device *dev,
0357                      struct snd_soc_dai_link *links,
0358                      struct snd_soc_dai_link_component *cpus,
0359                      int *id, int ssp_codec)
0360 {
0361     /* codec SSP */
0362     links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec",
0363                      ssp_codec);
0364     if (!links[*id].name)
0365         goto devm_err;
0366 
0367     links[*id].id = *id;
0368     links[*id].codecs = cs42l42_component;
0369     links[*id].num_codecs = ARRAY_SIZE(cs42l42_component);
0370     links[*id].platforms = platform_component;
0371     links[*id].num_platforms = ARRAY_SIZE(platform_component);
0372     links[*id].init = sof_cs42l42_init;
0373     links[*id].exit = sof_cs42l42_exit;
0374     links[*id].ops = &sof_cs42l42_ops;
0375     links[*id].dpcm_playback = 1;
0376     links[*id].dpcm_capture = 1;
0377     links[*id].no_pcm = 1;
0378     links[*id].cpus = &cpus[*id];
0379     links[*id].num_cpus = 1;
0380 
0381     links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
0382                            "SSP%d Pin",
0383                            ssp_codec);
0384     if (!links[*id].cpus->dai_name)
0385         goto devm_err;
0386 
0387     (*id)++;
0388 
0389     return 0;
0390 
0391 devm_err:
0392     return -ENOMEM;
0393 }
0394 
0395 static int create_dmic_dai_links(struct device *dev,
0396                  struct snd_soc_dai_link *links,
0397                  struct snd_soc_dai_link_component *cpus,
0398                  int *id, int dmic_be_num)
0399 {
0400     int i;
0401 
0402     /* dmic */
0403     if (dmic_be_num <= 0)
0404         return 0;
0405 
0406     /* at least we have dmic01 */
0407     links[*id].name = "dmic01";
0408     links[*id].cpus = &cpus[*id];
0409     links[*id].cpus->dai_name = "DMIC01 Pin";
0410     links[*id].init = dmic_init;
0411     if (dmic_be_num > 1) {
0412         /* set up 2 BE links at most */
0413         links[*id + 1].name = "dmic16k";
0414         links[*id + 1].cpus = &cpus[*id + 1];
0415         links[*id + 1].cpus->dai_name = "DMIC16k Pin";
0416         dmic_be_num = 2;
0417     }
0418 
0419     for (i = 0; i < dmic_be_num; i++) {
0420         links[*id].id = *id;
0421         links[*id].num_cpus = 1;
0422         links[*id].codecs = dmic_component;
0423         links[*id].num_codecs = ARRAY_SIZE(dmic_component);
0424         links[*id].platforms = platform_component;
0425         links[*id].num_platforms = ARRAY_SIZE(platform_component);
0426         links[*id].ignore_suspend = 1;
0427         links[*id].dpcm_capture = 1;
0428         links[*id].no_pcm = 1;
0429 
0430         (*id)++;
0431     }
0432 
0433     return 0;
0434 }
0435 
0436 static int create_hdmi_dai_links(struct device *dev,
0437                  struct snd_soc_dai_link *links,
0438                  struct snd_soc_dai_link_component *cpus,
0439                  int *id, int hdmi_num)
0440 {
0441     struct snd_soc_dai_link_component *idisp_components;
0442     int i;
0443 
0444     /* HDMI */
0445     if (hdmi_num <= 0)
0446         return 0;
0447 
0448     idisp_components = devm_kzalloc(dev,
0449                     sizeof(struct snd_soc_dai_link_component) *
0450                     hdmi_num, GFP_KERNEL);
0451     if (!idisp_components)
0452         goto devm_err;
0453 
0454     for (i = 1; i <= hdmi_num; i++) {
0455         links[*id].name = devm_kasprintf(dev, GFP_KERNEL,
0456                          "iDisp%d", i);
0457         if (!links[*id].name)
0458             goto devm_err;
0459 
0460         links[*id].id = *id;
0461         links[*id].cpus = &cpus[*id];
0462         links[*id].num_cpus = 1;
0463         links[*id].cpus->dai_name = devm_kasprintf(dev,
0464                                GFP_KERNEL,
0465                                "iDisp%d Pin",
0466                                i);
0467         if (!links[*id].cpus->dai_name)
0468             goto devm_err;
0469 
0470         idisp_components[i - 1].name = "ehdaudio0D2";
0471         idisp_components[i - 1].dai_name = devm_kasprintf(dev,
0472                                   GFP_KERNEL,
0473                                   "intel-hdmi-hifi%d",
0474                                   i);
0475         if (!idisp_components[i - 1].dai_name)
0476             goto devm_err;
0477 
0478         links[*id].codecs = &idisp_components[i - 1];
0479         links[*id].num_codecs = 1;
0480         links[*id].platforms = platform_component;
0481         links[*id].num_platforms = ARRAY_SIZE(platform_component);
0482         links[*id].init = sof_hdmi_init;
0483         links[*id].dpcm_playback = 1;
0484         links[*id].no_pcm = 1;
0485 
0486         (*id)++;
0487     }
0488 
0489     return 0;
0490 
0491 devm_err:
0492     return -ENOMEM;
0493 }
0494 
0495 static int create_bt_offload_dai_links(struct device *dev,
0496                        struct snd_soc_dai_link *links,
0497                        struct snd_soc_dai_link_component *cpus,
0498                        int *id, int ssp_bt)
0499 {
0500     /* bt offload */
0501     if (!(sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT))
0502         return 0;
0503 
0504     links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT",
0505                      ssp_bt);
0506     if (!links[*id].name)
0507         goto devm_err;
0508 
0509     links[*id].id = *id;
0510     links[*id].codecs = dummy_component;
0511     links[*id].num_codecs = ARRAY_SIZE(dummy_component);
0512     links[*id].platforms = platform_component;
0513     links[*id].num_platforms = ARRAY_SIZE(platform_component);
0514 
0515     links[*id].dpcm_playback = 1;
0516     links[*id].dpcm_capture = 1;
0517     links[*id].no_pcm = 1;
0518     links[*id].cpus = &cpus[*id];
0519     links[*id].num_cpus = 1;
0520 
0521     links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
0522                            "SSP%d Pin",
0523                            ssp_bt);
0524     if (!links[*id].cpus->dai_name)
0525         goto devm_err;
0526 
0527     (*id)++;
0528 
0529     return 0;
0530 
0531 devm_err:
0532     return -ENOMEM;
0533 }
0534 
0535 static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
0536                               int ssp_codec,
0537                               int ssp_amp,
0538                               int ssp_bt,
0539                               int dmic_be_num,
0540                               int hdmi_num)
0541 {
0542     struct snd_soc_dai_link_component *cpus;
0543     struct snd_soc_dai_link *links;
0544     int ret, id = 0, link_seq;
0545 
0546     links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
0547                  sof_audio_card_cs42l42.num_links, GFP_KERNEL);
0548     cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
0549                  sof_audio_card_cs42l42.num_links, GFP_KERNEL);
0550     if (!links || !cpus)
0551         goto devm_err;
0552 
0553     link_seq = (sof_cs42l42_quirk & SOF_CS42L42_DAILINK_MASK) >> SOF_CS42L42_DAILINK_SHIFT;
0554 
0555     while (link_seq) {
0556         int link_type = link_seq & 0x07;
0557 
0558         switch (link_type) {
0559         case LINK_HP:
0560             ret = create_hp_codec_dai_links(dev, links, cpus, &id, ssp_codec);
0561             if (ret < 0) {
0562                 dev_err(dev, "fail to create hp codec dai links, ret %d\n",
0563                     ret);
0564                 goto devm_err;
0565             }
0566             break;
0567         case LINK_SPK:
0568             ret = create_spk_amp_dai_links(dev, links, cpus, &id, ssp_amp);
0569             if (ret < 0) {
0570                 dev_err(dev, "fail to create spk amp dai links, ret %d\n",
0571                     ret);
0572                 goto devm_err;
0573             }
0574             break;
0575         case LINK_DMIC:
0576             ret = create_dmic_dai_links(dev, links, cpus, &id, dmic_be_num);
0577             if (ret < 0) {
0578                 dev_err(dev, "fail to create dmic dai links, ret %d\n",
0579                     ret);
0580                 goto devm_err;
0581             }
0582             break;
0583         case LINK_HDMI:
0584             ret = create_hdmi_dai_links(dev, links, cpus, &id, hdmi_num);
0585             if (ret < 0) {
0586                 dev_err(dev, "fail to create hdmi dai links, ret %d\n",
0587                     ret);
0588                 goto devm_err;
0589             }
0590             break;
0591         case LINK_BT:
0592             ret = create_bt_offload_dai_links(dev, links, cpus, &id, ssp_bt);
0593             if (ret < 0) {
0594                 dev_err(dev, "fail to create bt offload dai links, ret %d\n",
0595                     ret);
0596                 goto devm_err;
0597             }
0598             break;
0599         case LINK_NONE:
0600             /* caught here if it's not used as terminator in macro */
0601         default:
0602             dev_err(dev, "invalid link type %d\n", link_type);
0603             goto devm_err;
0604         }
0605 
0606         link_seq >>= 3;
0607     }
0608 
0609     return links;
0610 devm_err:
0611     return NULL;
0612 }
0613 
0614 static int sof_audio_probe(struct platform_device *pdev)
0615 {
0616     struct snd_soc_dai_link *dai_links;
0617     struct snd_soc_acpi_mach *mach;
0618     struct sof_card_private *ctx;
0619     int dmic_be_num, hdmi_num;
0620     int ret, ssp_bt, ssp_amp, ssp_codec;
0621 
0622     ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
0623     if (!ctx)
0624         return -ENOMEM;
0625 
0626     if (pdev->id_entry && pdev->id_entry->driver_data)
0627         sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data;
0628 
0629     mach = pdev->dev.platform_data;
0630 
0631     if (soc_intel_is_glk()) {
0632         dmic_be_num = 1;
0633         hdmi_num = 3;
0634     } else {
0635         dmic_be_num = 2;
0636         hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >>
0637              SOF_CS42L42_NUM_HDMIDEV_SHIFT;
0638         /* default number of HDMI DAI's */
0639         if (!hdmi_num)
0640             hdmi_num = 3;
0641     }
0642 
0643     dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
0644 
0645     ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >>
0646             SOF_CS42L42_SSP_BT_SHIFT;
0647 
0648     ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >>
0649             SOF_CS42L42_SSP_AMP_SHIFT;
0650 
0651     ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK;
0652 
0653     /* compute number of dai links */
0654     sof_audio_card_cs42l42.num_links = 1 + dmic_be_num + hdmi_num;
0655 
0656     if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT)
0657         sof_audio_card_cs42l42.num_links++;
0658     if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT)
0659         sof_audio_card_cs42l42.num_links++;
0660 
0661     dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
0662                           ssp_bt, dmic_be_num, hdmi_num);
0663     if (!dai_links)
0664         return -ENOMEM;
0665 
0666     sof_audio_card_cs42l42.dai_link = dai_links;
0667 
0668     INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
0669 
0670     sof_audio_card_cs42l42.dev = &pdev->dev;
0671 
0672     /* set platform name for each dailink */
0673     ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_cs42l42,
0674                             mach->mach_params.platform);
0675     if (ret)
0676         return ret;
0677 
0678     ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
0679 
0680     snd_soc_card_set_drvdata(&sof_audio_card_cs42l42, ctx);
0681 
0682     return devm_snd_soc_register_card(&pdev->dev,
0683                       &sof_audio_card_cs42l42);
0684 }
0685 
0686 static const struct platform_device_id board_ids[] = {
0687     {
0688         .name = "glk_cs4242_mx98357a",
0689         .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) |
0690                     SOF_SPEAKER_AMP_PRESENT |
0691                     SOF_MAX98357A_SPEAKER_AMP_PRESENT |
0692                     SOF_CS42L42_SSP_AMP(1)) |
0693                     SOF_CS42L42_DAILINK(LINK_SPK, LINK_HP, LINK_DMIC, LINK_HDMI, LINK_NONE),
0694     },
0695     {
0696         .name = "jsl_cs4242_mx98360a",
0697         .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
0698                     SOF_SPEAKER_AMP_PRESENT |
0699                     SOF_MAX98360A_SPEAKER_AMP_PRESENT |
0700                     SOF_CS42L42_SSP_AMP(1)) |
0701                     SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_NONE),
0702     },
0703     {
0704         .name = "adl_mx98360a_cs4242",
0705         .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
0706                 SOF_SPEAKER_AMP_PRESENT |
0707                 SOF_MAX98360A_SPEAKER_AMP_PRESENT |
0708                 SOF_CS42L42_SSP_AMP(1) |
0709                 SOF_CS42L42_NUM_HDMIDEV(4) |
0710                 SOF_BT_OFFLOAD_PRESENT |
0711                 SOF_CS42L42_SSP_BT(2) |
0712                 SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_BT)),
0713     },
0714     { }
0715 };
0716 MODULE_DEVICE_TABLE(platform, board_ids);
0717 
0718 static struct platform_driver sof_audio = {
0719     .probe = sof_audio_probe,
0720     .driver = {
0721         .name = "sof_cs42l42",
0722         .pm = &snd_soc_pm_ops,
0723     },
0724     .id_table = board_ids,
0725 };
0726 module_platform_driver(sof_audio)
0727 
0728 /* Module information */
0729 MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42");
0730 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
0731 MODULE_LICENSE("GPL");
0732 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
0733 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);