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