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