linux/sound/soc/qcom/sdm845.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
   4 */
   5
   6#include <linux/module.h>
   7#include <linux/platform_device.h>
   8#include <linux/of_device.h>
   9#include <sound/core.h>
  10#include <sound/pcm.h>
  11#include <sound/pcm_params.h>
  12#include <sound/jack.h>
  13#include <sound/soc.h>
  14#include <linux/soundwire/sdw.h>
  15#include <uapi/linux/input-event-codes.h>
  16#include "common.h"
  17#include "qdsp6/q6afe.h"
  18#include "../codecs/rt5663.h"
  19
  20#define DEFAULT_SAMPLE_RATE_48K         48000
  21#define DEFAULT_MCLK_RATE               24576000
  22#define TDM_BCLK_RATE           6144000
  23#define MI2S_BCLK_RATE          1536000
  24#define LEFT_SPK_TDM_TX_MASK    0x30
  25#define RIGHT_SPK_TDM_TX_MASK   0xC0
  26#define SPK_TDM_RX_MASK         0x03
  27#define NUM_TDM_SLOTS           8
  28#define SLIM_MAX_TX_PORTS 16
  29#define SLIM_MAX_RX_PORTS 16
  30#define WCD934X_DEFAULT_MCLK_RATE       9600000
  31
  32struct sdm845_snd_data {
  33        struct snd_soc_jack jack;
  34        bool jack_setup;
  35        bool stream_prepared[SLIM_MAX_RX_PORTS];
  36        struct snd_soc_card *card;
  37        uint32_t pri_mi2s_clk_count;
  38        uint32_t sec_mi2s_clk_count;
  39        uint32_t quat_tdm_clk_count;
  40        struct sdw_stream_runtime *sruntime[SLIM_MAX_RX_PORTS];
  41};
  42
  43static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
  44
  45static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream,
  46                                     struct snd_pcm_hw_params *params)
  47{
  48        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  49        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
  50        struct snd_soc_dai *codec_dai;
  51        struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
  52        u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
  53        struct sdw_stream_runtime *sruntime;
  54        u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
  55        int ret = 0, i;
  56
  57        for_each_rtd_codec_dais(rtd, i, codec_dai) {
  58                sruntime = snd_soc_dai_get_sdw_stream(codec_dai,
  59                                                      substream->stream);
  60                if (sruntime != ERR_PTR(-ENOTSUPP))
  61                        pdata->sruntime[cpu_dai->id] = sruntime;
  62
  63                ret = snd_soc_dai_get_channel_map(codec_dai,
  64                                &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
  65
  66                if (ret != 0 && ret != -ENOTSUPP) {
  67                        pr_err("failed to get codec chan map, err:%d\n", ret);
  68                        return ret;
  69                } else if (ret == -ENOTSUPP) {
  70                        /* Ignore unsupported */
  71                        continue;
  72                }
  73
  74                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  75                        ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
  76                                                          rx_ch_cnt, rx_ch);
  77                else
  78                        ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt,
  79                                                          tx_ch, 0, NULL);
  80        }
  81
  82        return 0;
  83}
  84
  85static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
  86                                        struct snd_pcm_hw_params *params)
  87{
  88        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  89        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
  90        struct snd_soc_dai *codec_dai;
  91        int ret = 0, j;
  92        int channels, slot_width;
  93
  94        switch (params_format(params)) {
  95        case SNDRV_PCM_FORMAT_S16_LE:
  96                slot_width = 16;
  97                break;
  98        default:
  99                dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
 100                                __func__, params_format(params));
 101                return -EINVAL;
 102        }
 103
 104        channels = params_channels(params);
 105        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 106                ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0x3,
 107                                8, slot_width);
 108                if (ret < 0) {
 109                        dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
 110                                        __func__, ret);
 111                        goto end;
 112                }
 113
 114                ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
 115                                channels, tdm_slot_offset);
 116                if (ret < 0) {
 117                        dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
 118                                        __func__, ret);
 119                        goto end;
 120                }
 121        } else {
 122                ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xf, 0,
 123                                8, slot_width);
 124                if (ret < 0) {
 125                        dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
 126                                        __func__, ret);
 127                        goto end;
 128                }
 129
 130                ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
 131                                tdm_slot_offset, 0, NULL);
 132                if (ret < 0) {
 133                        dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
 134                                        __func__, ret);
 135                        goto end;
 136                }
 137        }
 138
 139        for_each_rtd_codec_dais(rtd, j, codec_dai) {
 140
 141                if (!strcmp(codec_dai->component->name_prefix, "Left")) {
 142                        ret = snd_soc_dai_set_tdm_slot(
 143                                        codec_dai, LEFT_SPK_TDM_TX_MASK,
 144                                        SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
 145                                        slot_width);
 146                        if (ret < 0) {
 147                                dev_err(rtd->dev,
 148                                        "DEV0 TDM slot err:%d\n", ret);
 149                                return ret;
 150                        }
 151                }
 152
 153                if (!strcmp(codec_dai->component->name_prefix, "Right")) {
 154                        ret = snd_soc_dai_set_tdm_slot(
 155                                        codec_dai, RIGHT_SPK_TDM_TX_MASK,
 156                                        SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
 157                                        slot_width);
 158                        if (ret < 0) {
 159                                dev_err(rtd->dev,
 160                                        "DEV1 TDM slot err:%d\n", ret);
 161                                return ret;
 162                        }
 163                }
 164        }
 165
 166end:
 167        return ret;
 168}
 169
 170static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
 171                                        struct snd_pcm_hw_params *params)
 172{
 173        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 174        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 175        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 176        int ret = 0;
 177
 178        switch (cpu_dai->id) {
 179        case PRIMARY_MI2S_RX:
 180        case PRIMARY_MI2S_TX:
 181                /*
 182                 * Use ASRC for internal clocks, as PLL rate isn't multiple
 183                 * of BCLK.
 184                 */
 185                rt5663_sel_asrc_clk_src(
 186                        codec_dai->component,
 187                        RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
 188                        RT5663_CLK_SEL_I2S1_ASRC);
 189                ret = snd_soc_dai_set_sysclk(
 190                        codec_dai, RT5663_SCLK_S_MCLK, DEFAULT_MCLK_RATE,
 191                        SND_SOC_CLOCK_IN);
 192                if (ret < 0)
 193                        dev_err(rtd->dev,
 194                                "snd_soc_dai_set_sysclk err = %d\n", ret);
 195                break;
 196        case QUATERNARY_TDM_RX_0:
 197        case QUATERNARY_TDM_TX_0:
 198                ret = sdm845_tdm_snd_hw_params(substream, params);
 199                break;
 200        case SLIMBUS_0_RX...SLIMBUS_6_TX:
 201                ret = sdm845_slim_snd_hw_params(substream, params);
 202                break;
 203        case QUATERNARY_MI2S_RX:
 204                break;
 205        default:
 206                pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
 207                break;
 208        }
 209        return ret;
 210}
 211
 212static void sdm845_jack_free(struct snd_jack *jack)
 213{
 214        struct snd_soc_component *component = jack->private_data;
 215
 216        snd_soc_component_set_jack(component, NULL, NULL);
 217}
 218
 219static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
 220{
 221        struct snd_soc_component *component;
 222        struct snd_soc_card *card = rtd->card;
 223        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 224        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 225        struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
 226        struct snd_jack *jack;
 227        /*
 228         * Codec SLIMBUS configuration
 229         * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
 230         * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
 231         * TX14, TX15, TX16
 232         */
 233        unsigned int rx_ch[SLIM_MAX_RX_PORTS] = {144, 145, 146, 147, 148, 149,
 234                                        150, 151, 152, 153, 154, 155, 156};
 235        unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133,
 236                                            134, 135, 136, 137, 138, 139,
 237                                            140, 141, 142, 143};
 238        int rval, i;
 239
 240
 241        if (!pdata->jack_setup) {
 242                rval = snd_soc_card_jack_new(card, "Headset Jack",
 243                                SND_JACK_HEADSET |
 244                                SND_JACK_HEADPHONE |
 245                                SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 246                                SND_JACK_BTN_2 | SND_JACK_BTN_3,
 247                                &pdata->jack, NULL, 0);
 248
 249                if (rval < 0) {
 250                        dev_err(card->dev, "Unable to add Headphone Jack\n");
 251                        return rval;
 252                }
 253
 254                jack = pdata->jack.jack;
 255
 256                snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
 257                snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
 258                snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
 259                snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 260                pdata->jack_setup = true;
 261        }
 262
 263        switch (cpu_dai->id) {
 264        case PRIMARY_MI2S_RX:
 265                jack  = pdata->jack.jack;
 266                component = codec_dai->component;
 267
 268                jack->private_data = component;
 269                jack->private_free = sdm845_jack_free;
 270                rval = snd_soc_component_set_jack(component,
 271                                                  &pdata->jack, NULL);
 272                if (rval != 0 && rval != -ENOTSUPP) {
 273                        dev_warn(card->dev, "Failed to set jack: %d\n", rval);
 274                        return rval;
 275                }
 276                break;
 277        case SLIMBUS_0_RX...SLIMBUS_6_TX:
 278                for_each_rtd_codec_dais(rtd, i, codec_dai) {
 279                        rval = snd_soc_dai_set_channel_map(codec_dai,
 280                                                          ARRAY_SIZE(tx_ch),
 281                                                          tx_ch,
 282                                                          ARRAY_SIZE(rx_ch),
 283                                                          rx_ch);
 284                        if (rval != 0 && rval != -ENOTSUPP)
 285                                return rval;
 286
 287                        snd_soc_dai_set_sysclk(codec_dai, 0,
 288                                               WCD934X_DEFAULT_MCLK_RATE,
 289                                               SNDRV_PCM_STREAM_PLAYBACK);
 290                }
 291                break;
 292        default:
 293                break;
 294        }
 295
 296        return 0;
 297}
 298
 299
 300static int sdm845_snd_startup(struct snd_pcm_substream *substream)
 301{
 302        unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
 303        unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
 304        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 305        struct snd_soc_card *card = rtd->card;
 306        struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
 307        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 308        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 309        int j;
 310        int ret;
 311
 312        switch (cpu_dai->id) {
 313        case PRIMARY_MI2S_RX:
 314        case PRIMARY_MI2S_TX:
 315                codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF;
 316                if (++(data->pri_mi2s_clk_count) == 1) {
 317                        snd_soc_dai_set_sysclk(cpu_dai,
 318                                Q6AFE_LPASS_CLK_ID_MCLK_1,
 319                                DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
 320                        snd_soc_dai_set_sysclk(cpu_dai,
 321                                Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
 322                                MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
 323                }
 324                snd_soc_dai_set_fmt(cpu_dai, fmt);
 325                snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
 326                break;
 327
 328        case SECONDARY_MI2S_TX:
 329                codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
 330                if (++(data->sec_mi2s_clk_count) == 1) {
 331                        snd_soc_dai_set_sysclk(cpu_dai,
 332                                Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
 333                                MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE);
 334                }
 335                snd_soc_dai_set_fmt(cpu_dai, fmt);
 336                snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
 337                break;
 338        case QUATERNARY_MI2S_RX:
 339                snd_soc_dai_set_sysclk(cpu_dai,
 340                        Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
 341                        MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
 342                snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
 343
 344
 345                break;
 346
 347        case QUATERNARY_TDM_RX_0:
 348        case QUATERNARY_TDM_TX_0:
 349                if (++(data->quat_tdm_clk_count) == 1) {
 350                        snd_soc_dai_set_sysclk(cpu_dai,
 351                                Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
 352                                TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
 353                }
 354
 355                codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
 356
 357                for_each_rtd_codec_dais(rtd, j, codec_dai) {
 358
 359                        if (!strcmp(codec_dai->component->name_prefix,
 360                                    "Left")) {
 361                                ret = snd_soc_dai_set_fmt(
 362                                                codec_dai, codec_dai_fmt);
 363                                if (ret < 0) {
 364                                        dev_err(rtd->dev,
 365                                                "Left TDM fmt err:%d\n", ret);
 366                                        return ret;
 367                                }
 368                        }
 369
 370                        if (!strcmp(codec_dai->component->name_prefix,
 371                                    "Right")) {
 372                                ret = snd_soc_dai_set_fmt(
 373                                                codec_dai, codec_dai_fmt);
 374                                if (ret < 0) {
 375                                        dev_err(rtd->dev,
 376                                                "Right TDM slot err:%d\n", ret);
 377                                        return ret;
 378                                }
 379                        }
 380                }
 381                break;
 382        case SLIMBUS_0_RX...SLIMBUS_6_TX:
 383                break;
 384
 385        default:
 386                pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
 387                break;
 388        }
 389        return 0;
 390}
 391
 392static void  sdm845_snd_shutdown(struct snd_pcm_substream *substream)
 393{
 394        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 395        struct snd_soc_card *card = rtd->card;
 396        struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
 397        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 398
 399        switch (cpu_dai->id) {
 400        case PRIMARY_MI2S_RX:
 401        case PRIMARY_MI2S_TX:
 402                if (--(data->pri_mi2s_clk_count) == 0) {
 403                        snd_soc_dai_set_sysclk(cpu_dai,
 404                                Q6AFE_LPASS_CLK_ID_MCLK_1,
 405                                0, SNDRV_PCM_STREAM_PLAYBACK);
 406                        snd_soc_dai_set_sysclk(cpu_dai,
 407                                Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
 408                                0, SNDRV_PCM_STREAM_PLAYBACK);
 409                }
 410                break;
 411
 412        case SECONDARY_MI2S_TX:
 413                if (--(data->sec_mi2s_clk_count) == 0) {
 414                        snd_soc_dai_set_sysclk(cpu_dai,
 415                                Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
 416                                0, SNDRV_PCM_STREAM_CAPTURE);
 417                }
 418                break;
 419
 420        case QUATERNARY_TDM_RX_0:
 421        case QUATERNARY_TDM_TX_0:
 422                if (--(data->quat_tdm_clk_count) == 0) {
 423                        snd_soc_dai_set_sysclk(cpu_dai,
 424                                Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
 425                                0, SNDRV_PCM_STREAM_PLAYBACK);
 426                }
 427                break;
 428        case SLIMBUS_0_RX...SLIMBUS_6_TX:
 429        case QUATERNARY_MI2S_RX:
 430                break;
 431
 432        default:
 433                pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
 434                break;
 435        }
 436}
 437
 438static int sdm845_snd_prepare(struct snd_pcm_substream *substream)
 439{
 440        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 441        struct sdm845_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
 442        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 443        struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
 444        int ret;
 445
 446        if (!sruntime)
 447                return 0;
 448
 449        if (data->stream_prepared[cpu_dai->id]) {
 450                sdw_disable_stream(sruntime);
 451                sdw_deprepare_stream(sruntime);
 452                data->stream_prepared[cpu_dai->id] = false;
 453        }
 454
 455        ret = sdw_prepare_stream(sruntime);
 456        if (ret)
 457                return ret;
 458
 459        /**
 460         * NOTE: there is a strict hw requirement about the ordering of port
 461         * enables and actual WSA881x PA enable. PA enable should only happen
 462         * after soundwire ports are enabled if not DC on the line is
 463         * accumulated resulting in Click/Pop Noise
 464         * PA enable/mute are handled as part of codec DAPM and digital mute.
 465         */
 466
 467        ret = sdw_enable_stream(sruntime);
 468        if (ret) {
 469                sdw_deprepare_stream(sruntime);
 470                return ret;
 471        }
 472        data->stream_prepared[cpu_dai->id] = true;
 473
 474        return ret;
 475}
 476
 477static int sdm845_snd_hw_free(struct snd_pcm_substream *substream)
 478{
 479        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 480        struct sdm845_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
 481        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 482        struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
 483
 484        if (sruntime && data->stream_prepared[cpu_dai->id]) {
 485                sdw_disable_stream(sruntime);
 486                sdw_deprepare_stream(sruntime);
 487                data->stream_prepared[cpu_dai->id] = false;
 488        }
 489
 490        return 0;
 491}
 492
 493static const struct snd_soc_ops sdm845_be_ops = {
 494        .hw_params = sdm845_snd_hw_params,
 495        .hw_free = sdm845_snd_hw_free,
 496        .prepare = sdm845_snd_prepare,
 497        .startup = sdm845_snd_startup,
 498        .shutdown = sdm845_snd_shutdown,
 499};
 500
 501static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 502                                struct snd_pcm_hw_params *params)
 503{
 504        struct snd_interval *rate = hw_param_interval(params,
 505                                        SNDRV_PCM_HW_PARAM_RATE);
 506        struct snd_interval *channels = hw_param_interval(params,
 507                                        SNDRV_PCM_HW_PARAM_CHANNELS);
 508        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 509
 510        rate->min = rate->max = DEFAULT_SAMPLE_RATE_48K;
 511        channels->min = channels->max = 2;
 512        snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
 513
 514        return 0;
 515}
 516
 517static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = {
 518        SND_SOC_DAPM_HP("Headphone Jack", NULL),
 519        SND_SOC_DAPM_MIC("Headset Mic", NULL),
 520        SND_SOC_DAPM_SPK("Left Spk", NULL),
 521        SND_SOC_DAPM_SPK("Right Spk", NULL),
 522        SND_SOC_DAPM_MIC("Int Mic", NULL),
 523};
 524
 525static void sdm845_add_ops(struct snd_soc_card *card)
 526{
 527        struct snd_soc_dai_link *link;
 528        int i;
 529
 530        for_each_card_prelinks(card, i, link) {
 531                if (link->no_pcm == 1) {
 532                        link->ops = &sdm845_be_ops;
 533                        link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
 534                }
 535                link->init = sdm845_dai_init;
 536        }
 537}
 538
 539static int sdm845_snd_platform_probe(struct platform_device *pdev)
 540{
 541        struct snd_soc_card *card;
 542        struct sdm845_snd_data *data;
 543        struct device *dev = &pdev->dev;
 544        int ret;
 545
 546        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
 547        if (!card)
 548                return -ENOMEM;
 549
 550        /* Allocate the private data */
 551        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 552        if (!data)
 553                return -ENOMEM;
 554
 555        card->dapm_widgets = sdm845_snd_widgets;
 556        card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
 557        card->dev = dev;
 558        card->owner = THIS_MODULE;
 559        dev_set_drvdata(dev, card);
 560        ret = qcom_snd_parse_of(card);
 561        if (ret)
 562                return ret;
 563
 564        data->card = card;
 565        snd_soc_card_set_drvdata(card, data);
 566
 567        sdm845_add_ops(card);
 568        return devm_snd_soc_register_card(dev, card);
 569}
 570
 571static const struct of_device_id sdm845_snd_device_id[]  = {
 572        { .compatible = "qcom,sdm845-sndcard" },
 573        { .compatible = "qcom,db845c-sndcard" },
 574        { .compatible = "lenovo,yoga-c630-sndcard" },
 575        {},
 576};
 577MODULE_DEVICE_TABLE(of, sdm845_snd_device_id);
 578
 579static struct platform_driver sdm845_snd_driver = {
 580        .probe = sdm845_snd_platform_probe,
 581        .driver = {
 582                .name = "msm-snd-sdm845",
 583                .of_match_table = sdm845_snd_device_id,
 584        },
 585};
 586module_platform_driver(sdm845_snd_driver);
 587
 588MODULE_DESCRIPTION("sdm845 ASoC Machine Driver");
 589MODULE_LICENSE("GPL v2");
 590