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