brintos

brintos / linux-shallow public Read only

0
0
Text · 16.9 KiB · a479d7e Raw
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