cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sdm845.c (16501B)


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