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