Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/qcom/qdsp6/topology.c
26444 views
1
// SPDX-License-Identifier: GPL-2.0
2
// Copyright (c) 2020, Linaro Limited
3
4
#include <linux/cleanup.h>
5
#include <sound/soc.h>
6
#include <sound/soc-dapm.h>
7
#include <sound/pcm.h>
8
#include <sound/control.h>
9
#include <sound/asound.h>
10
#include <linux/firmware.h>
11
#include <sound/soc-topology.h>
12
#include <sound/soc-dpcm.h>
13
#include <uapi/sound/snd_ar_tokens.h>
14
#include <linux/kernel.h>
15
#include <linux/wait.h>
16
#include "q6apm.h"
17
#include "audioreach.h"
18
19
struct snd_ar_control {
20
u32 graph_id; /* Graph ID */
21
u32 sgid; /* Sub Graph ID */
22
u32 module_instance_id; /* Connected Module Instance ID */
23
struct snd_soc_dapm_widget *w;
24
struct list_head node;
25
struct snd_soc_component *scomp;
26
};
27
28
static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6apm *apm,
29
uint32_t graph_id,
30
bool *found)
31
{
32
struct audioreach_graph_info *info;
33
int ret;
34
35
mutex_lock(&apm->lock);
36
info = idr_find(&apm->graph_info_idr, graph_id);
37
mutex_unlock(&apm->lock);
38
39
if (info) {
40
*found = true;
41
return info;
42
}
43
44
*found = false;
45
info = kzalloc(sizeof(*info), GFP_KERNEL);
46
if (!info)
47
return ERR_PTR(-ENOMEM);
48
49
INIT_LIST_HEAD(&info->sg_list);
50
51
mutex_lock(&apm->lock);
52
ret = idr_alloc_u32(&apm->graph_info_idr, info, &graph_id, graph_id, GFP_KERNEL);
53
mutex_unlock(&apm->lock);
54
55
if (ret < 0) {
56
dev_err(apm->dev, "Failed to allocate Graph ID (%x)\n", graph_id);
57
kfree(info);
58
return ERR_PTR(ret);
59
}
60
61
info->id = graph_id;
62
63
return info;
64
}
65
66
static void audioreach_tplg_add_sub_graph(struct audioreach_sub_graph *sg,
67
struct audioreach_graph_info *info)
68
{
69
list_add_tail(&sg->node, &info->sg_list);
70
sg->info = info;
71
info->num_sub_graphs++;
72
}
73
74
static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm *apm,
75
uint32_t sub_graph_id,
76
bool *found)
77
{
78
struct audioreach_sub_graph *sg;
79
int ret;
80
81
if (!sub_graph_id)
82
return ERR_PTR(-EINVAL);
83
84
/* Find if there is already a matching sub-graph */
85
mutex_lock(&apm->lock);
86
sg = idr_find(&apm->sub_graphs_idr, sub_graph_id);
87
mutex_unlock(&apm->lock);
88
89
if (sg) {
90
*found = true;
91
return sg;
92
}
93
94
*found = false;
95
sg = kzalloc(sizeof(*sg), GFP_KERNEL);
96
if (!sg)
97
return ERR_PTR(-ENOMEM);
98
99
INIT_LIST_HEAD(&sg->container_list);
100
101
mutex_lock(&apm->lock);
102
ret = idr_alloc_u32(&apm->sub_graphs_idr, sg, &sub_graph_id, sub_graph_id, GFP_KERNEL);
103
mutex_unlock(&apm->lock);
104
105
if (ret < 0) {
106
dev_err(apm->dev, "Failed to allocate Sub-Graph Instance ID (%x)\n", sub_graph_id);
107
kfree(sg);
108
return ERR_PTR(ret);
109
}
110
111
sg->sub_graph_id = sub_graph_id;
112
113
return sg;
114
}
115
116
static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm *apm,
117
struct audioreach_sub_graph *sg,
118
uint32_t container_id,
119
bool *found)
120
{
121
struct audioreach_container *cont;
122
int ret;
123
124
if (!container_id)
125
return ERR_PTR(-EINVAL);
126
127
mutex_lock(&apm->lock);
128
cont = idr_find(&apm->containers_idr, container_id);
129
mutex_unlock(&apm->lock);
130
131
if (cont) {
132
*found = true;
133
return cont;
134
}
135
*found = false;
136
137
cont = kzalloc(sizeof(*cont), GFP_KERNEL);
138
if (!cont)
139
return ERR_PTR(-ENOMEM);
140
141
INIT_LIST_HEAD(&cont->modules_list);
142
143
mutex_lock(&apm->lock);
144
ret = idr_alloc_u32(&apm->containers_idr, cont, &container_id, container_id, GFP_KERNEL);
145
mutex_unlock(&apm->lock);
146
147
if (ret < 0) {
148
dev_err(apm->dev, "Failed to allocate Container Instance ID (%x)\n", container_id);
149
kfree(cont);
150
return ERR_PTR(ret);
151
}
152
153
cont->container_id = container_id;
154
cont->sub_graph = sg;
155
/* add to container list */
156
list_add_tail(&cont->node, &sg->container_list);
157
sg->num_containers++;
158
159
return cont;
160
}
161
162
static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm,
163
struct audioreach_container *cont,
164
struct snd_soc_dapm_widget *w,
165
uint32_t module_id, bool *found)
166
{
167
struct audioreach_module *mod;
168
int ret;
169
170
mutex_lock(&apm->lock);
171
mod = idr_find(&apm->modules_idr, module_id);
172
mutex_unlock(&apm->lock);
173
174
if (mod) {
175
*found = true;
176
return mod;
177
}
178
*found = false;
179
mod = kzalloc(sizeof(*mod), GFP_KERNEL);
180
if (!mod)
181
return ERR_PTR(-ENOMEM);
182
183
mutex_lock(&apm->lock);
184
if (!module_id) { /* alloc module id dynamically */
185
ret = idr_alloc_cyclic(&apm->modules_idr, mod,
186
AR_MODULE_DYNAMIC_INSTANCE_ID_START,
187
AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL);
188
} else {
189
ret = idr_alloc_u32(&apm->modules_idr, mod, &module_id, module_id, GFP_KERNEL);
190
}
191
mutex_unlock(&apm->lock);
192
193
if (ret < 0) {
194
dev_err(apm->dev, "Failed to allocate Module Instance ID (%x)\n", module_id);
195
kfree(mod);
196
return ERR_PTR(ret);
197
}
198
199
mod->instance_id = module_id;
200
/* add to module list */
201
list_add_tail(&mod->node, &cont->modules_list);
202
mod->container = cont;
203
mod->widget = w;
204
cont->num_modules++;
205
206
return mod;
207
}
208
209
static struct snd_soc_tplg_vendor_array *audioreach_get_sg_array(
210
struct snd_soc_tplg_private *private)
211
{
212
struct snd_soc_tplg_vendor_array *sg_array = NULL;
213
bool found = false;
214
int sz;
215
216
for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
217
struct snd_soc_tplg_vendor_value_elem *sg_elem;
218
int tkn_count = 0;
219
220
sg_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
221
sg_elem = sg_array->value;
222
sz = sz + le32_to_cpu(sg_array->size);
223
while (!found && tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) {
224
switch (le32_to_cpu(sg_elem->token)) {
225
case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
226
found = true;
227
break;
228
default:
229
break;
230
}
231
tkn_count++;
232
sg_elem++;
233
}
234
}
235
236
if (found)
237
return sg_array;
238
239
return NULL;
240
}
241
242
static struct snd_soc_tplg_vendor_array *audioreach_get_cont_array(
243
struct snd_soc_tplg_private *private)
244
{
245
struct snd_soc_tplg_vendor_array *cont_array = NULL;
246
bool found = false;
247
int sz;
248
249
for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
250
struct snd_soc_tplg_vendor_value_elem *cont_elem;
251
int tkn_count = 0;
252
253
cont_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
254
cont_elem = cont_array->value;
255
sz = sz + le32_to_cpu(cont_array->size);
256
while (!found && tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) {
257
switch (le32_to_cpu(cont_elem->token)) {
258
case AR_TKN_U32_CONTAINER_INSTANCE_ID:
259
found = true;
260
break;
261
default:
262
break;
263
}
264
tkn_count++;
265
cont_elem++;
266
}
267
}
268
269
if (found)
270
return cont_array;
271
272
return NULL;
273
}
274
275
static struct snd_soc_tplg_vendor_array *audioreach_get_module_array(
276
struct snd_soc_tplg_private *private)
277
{
278
struct snd_soc_tplg_vendor_array *mod_array = NULL;
279
bool found = false;
280
int sz = 0;
281
282
for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
283
struct snd_soc_tplg_vendor_value_elem *mod_elem;
284
int tkn_count = 0;
285
286
mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
287
mod_elem = mod_array->value;
288
sz = sz + le32_to_cpu(mod_array->size);
289
while (!found && tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
290
switch (le32_to_cpu(mod_elem->token)) {
291
case AR_TKN_U32_MODULE_INSTANCE_ID:
292
found = true;
293
break;
294
default:
295
break;
296
}
297
tkn_count++;
298
mod_elem++;
299
}
300
}
301
302
if (found)
303
return mod_array;
304
305
return NULL;
306
}
307
308
static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm,
309
struct snd_soc_tplg_private *private)
310
{
311
struct snd_soc_tplg_vendor_value_elem *sg_elem;
312
struct snd_soc_tplg_vendor_array *sg_array;
313
struct audioreach_graph_info *info = NULL;
314
int graph_id, sub_graph_id, tkn_count = 0;
315
struct audioreach_sub_graph *sg;
316
bool found;
317
318
sg_array = audioreach_get_sg_array(private);
319
sg_elem = sg_array->value;
320
321
while (tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) {
322
switch (le32_to_cpu(sg_elem->token)) {
323
case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
324
sub_graph_id = le32_to_cpu(sg_elem->value);
325
sg = audioreach_tplg_alloc_sub_graph(apm, sub_graph_id, &found);
326
if (IS_ERR(sg)) {
327
return sg;
328
} else if (found) {
329
/* Already parsed data for this sub-graph */
330
return sg;
331
}
332
break;
333
case AR_TKN_DAI_INDEX:
334
/* Sub graph is associated with predefined graph */
335
graph_id = le32_to_cpu(sg_elem->value);
336
info = audioreach_tplg_alloc_graph_info(apm, graph_id, &found);
337
if (IS_ERR(info))
338
return ERR_CAST(info);
339
break;
340
case AR_TKN_U32_SUB_GRAPH_PERF_MODE:
341
sg->perf_mode = le32_to_cpu(sg_elem->value);
342
break;
343
case AR_TKN_U32_SUB_GRAPH_DIRECTION:
344
sg->direction = le32_to_cpu(sg_elem->value);
345
break;
346
case AR_TKN_U32_SUB_GRAPH_SCENARIO_ID:
347
sg->scenario_id = le32_to_cpu(sg_elem->value);
348
break;
349
default:
350
dev_err(apm->dev, "Not a valid token %d for graph\n", sg_elem->token);
351
break;
352
353
}
354
tkn_count++;
355
sg_elem++;
356
}
357
358
/* Sub graph is associated with predefined graph */
359
if (info)
360
audioreach_tplg_add_sub_graph(sg, info);
361
362
return sg;
363
}
364
365
static struct audioreach_container *audioreach_parse_cont_tokens(struct q6apm *apm,
366
struct audioreach_sub_graph *sg,
367
struct snd_soc_tplg_private *private)
368
{
369
struct snd_soc_tplg_vendor_value_elem *cont_elem;
370
struct snd_soc_tplg_vendor_array *cont_array;
371
struct audioreach_container *cont;
372
int container_id, tkn_count = 0;
373
bool found = false;
374
375
cont_array = audioreach_get_cont_array(private);
376
cont_elem = cont_array->value;
377
378
while (tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) {
379
switch (le32_to_cpu(cont_elem->token)) {
380
case AR_TKN_U32_CONTAINER_INSTANCE_ID:
381
container_id = le32_to_cpu(cont_elem->value);
382
cont = audioreach_tplg_alloc_container(apm, sg, container_id, &found);
383
if (IS_ERR(cont) || found)/* Error or Already parsed container data */
384
return cont;
385
break;
386
case AR_TKN_U32_CONTAINER_CAPABILITY_ID:
387
cont->capability_id = le32_to_cpu(cont_elem->value);
388
break;
389
case AR_TKN_U32_CONTAINER_STACK_SIZE:
390
cont->stack_size = le32_to_cpu(cont_elem->value);
391
break;
392
case AR_TKN_U32_CONTAINER_GRAPH_POS:
393
cont->graph_pos = le32_to_cpu(cont_elem->value);
394
break;
395
case AR_TKN_U32_CONTAINER_PROC_DOMAIN:
396
cont->proc_domain = le32_to_cpu(cont_elem->value);
397
break;
398
default:
399
dev_err(apm->dev, "Not a valid token %d for graph\n", cont_elem->token);
400
break;
401
402
}
403
tkn_count++;
404
cont_elem++;
405
}
406
407
return cont;
408
}
409
410
static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *apm,
411
struct audioreach_container *cont,
412
struct snd_soc_tplg_private *private,
413
struct snd_soc_dapm_widget *w)
414
{
415
uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0;
416
uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS] = { 0, };
417
uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS] = { 0, };
418
uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS] = { 0, };
419
uint32_t src_mod_inst_id = 0;
420
421
int module_id = 0, instance_id = 0, tkn_count = 0;
422
struct snd_soc_tplg_vendor_value_elem *mod_elem;
423
struct snd_soc_tplg_vendor_array *mod_array;
424
struct audioreach_module *mod = NULL;
425
uint32_t token;
426
bool found;
427
int max_tokens;
428
429
mod_array = audioreach_get_module_array(private);
430
mod_elem = mod_array->value;
431
max_tokens = le32_to_cpu(mod_array->num_elems);
432
while (tkn_count <= (max_tokens - 1)) {
433
token = le32_to_cpu(mod_elem->token);
434
switch (token) {
435
/* common module info */
436
case AR_TKN_U32_MODULE_ID:
437
module_id = le32_to_cpu(mod_elem->value);
438
break;
439
case AR_TKN_U32_MODULE_INSTANCE_ID:
440
instance_id = le32_to_cpu(mod_elem->value);
441
mod = audioreach_tplg_alloc_module(apm, cont, w,
442
instance_id, &found);
443
if (IS_ERR(mod)) {
444
return mod;
445
} else if (found) {
446
dev_err(apm->dev, "Duplicate Module Instance ID 0x%08x found\n",
447
instance_id);
448
return ERR_PTR(-EINVAL);
449
}
450
451
break;
452
case AR_TKN_U32_MODULE_MAX_IP_PORTS:
453
max_ip_port = le32_to_cpu(mod_elem->value);
454
break;
455
case AR_TKN_U32_MODULE_MAX_OP_PORTS:
456
max_op_port = le32_to_cpu(mod_elem->value);
457
break;
458
case AR_TKN_U32_MODULE_IN_PORTS:
459
in_port = le32_to_cpu(mod_elem->value);
460
break;
461
case AR_TKN_U32_MODULE_OUT_PORTS:
462
out_port = le32_to_cpu(mod_elem->value);
463
break;
464
case AR_TKN_U32_MODULE_SRC_INSTANCE_ID:
465
src_mod_inst_id = le32_to_cpu(mod_elem->value);
466
break;
467
case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
468
src_mod_op_port_id[0] = le32_to_cpu(mod_elem->value);
469
break;
470
case AR_TKN_U32_MODULE_SRC_OP_PORT_ID1:
471
src_mod_op_port_id[1] = le32_to_cpu(mod_elem->value);
472
break;
473
case AR_TKN_U32_MODULE_SRC_OP_PORT_ID2:
474
src_mod_op_port_id[2] = le32_to_cpu(mod_elem->value);
475
break;
476
case AR_TKN_U32_MODULE_SRC_OP_PORT_ID3:
477
src_mod_op_port_id[3] = le32_to_cpu(mod_elem->value);
478
break;
479
case AR_TKN_U32_MODULE_SRC_OP_PORT_ID4:
480
src_mod_op_port_id[4] = le32_to_cpu(mod_elem->value);
481
break;
482
case AR_TKN_U32_MODULE_SRC_OP_PORT_ID5:
483
src_mod_op_port_id[5] = le32_to_cpu(mod_elem->value);
484
break;
485
case AR_TKN_U32_MODULE_SRC_OP_PORT_ID6:
486
src_mod_op_port_id[6] = le32_to_cpu(mod_elem->value);
487
break;
488
case AR_TKN_U32_MODULE_SRC_OP_PORT_ID7:
489
src_mod_op_port_id[7] = le32_to_cpu(mod_elem->value);
490
break;
491
case AR_TKN_U32_MODULE_DST_INSTANCE_ID:
492
dst_mod_inst_id[0] = le32_to_cpu(mod_elem->value);
493
break;
494
case AR_TKN_U32_MODULE_DST_INSTANCE_ID1:
495
dst_mod_inst_id[1] = le32_to_cpu(mod_elem->value);
496
break;
497
case AR_TKN_U32_MODULE_DST_INSTANCE_ID2:
498
dst_mod_inst_id[2] = le32_to_cpu(mod_elem->value);
499
break;
500
case AR_TKN_U32_MODULE_DST_INSTANCE_ID3:
501
dst_mod_inst_id[3] = le32_to_cpu(mod_elem->value);
502
break;
503
case AR_TKN_U32_MODULE_DST_INSTANCE_ID4:
504
dst_mod_inst_id[4] = le32_to_cpu(mod_elem->value);
505
break;
506
case AR_TKN_U32_MODULE_DST_INSTANCE_ID5:
507
dst_mod_inst_id[5] = le32_to_cpu(mod_elem->value);
508
break;
509
case AR_TKN_U32_MODULE_DST_INSTANCE_ID6:
510
dst_mod_inst_id[6] = le32_to_cpu(mod_elem->value);
511
break;
512
case AR_TKN_U32_MODULE_DST_INSTANCE_ID7:
513
dst_mod_inst_id[7] = le32_to_cpu(mod_elem->value);
514
break;
515
case AR_TKN_U32_MODULE_DST_IN_PORT_ID:
516
dst_mod_ip_port_id[0] = le32_to_cpu(mod_elem->value);
517
break;
518
case AR_TKN_U32_MODULE_DST_IN_PORT_ID1:
519
dst_mod_ip_port_id[1] = le32_to_cpu(mod_elem->value);
520
break;
521
case AR_TKN_U32_MODULE_DST_IN_PORT_ID2:
522
dst_mod_ip_port_id[2] = le32_to_cpu(mod_elem->value);
523
break;
524
case AR_TKN_U32_MODULE_DST_IN_PORT_ID3:
525
dst_mod_ip_port_id[3] = le32_to_cpu(mod_elem->value);
526
break;
527
case AR_TKN_U32_MODULE_DST_IN_PORT_ID4:
528
dst_mod_ip_port_id[4] = le32_to_cpu(mod_elem->value);
529
break;
530
case AR_TKN_U32_MODULE_DST_IN_PORT_ID5:
531
dst_mod_ip_port_id[5] = le32_to_cpu(mod_elem->value);
532
break;
533
case AR_TKN_U32_MODULE_DST_IN_PORT_ID6:
534
dst_mod_ip_port_id[6] = le32_to_cpu(mod_elem->value);
535
break;
536
case AR_TKN_U32_MODULE_DST_IN_PORT_ID7:
537
dst_mod_ip_port_id[7] = le32_to_cpu(mod_elem->value);
538
break;
539
default:
540
break;
541
542
}
543
tkn_count++;
544
mod_elem++;
545
}
546
547
if (mod) {
548
int pn, id = 0;
549
550
mod->module_id = module_id;
551
mod->max_ip_port = max_ip_port;
552
mod->max_op_port = max_op_port;
553
mod->in_port = in_port;
554
mod->out_port = out_port;
555
mod->src_mod_inst_id = src_mod_inst_id;
556
for (pn = 0; pn < mod->max_op_port; pn++) {
557
if (src_mod_op_port_id[pn] && dst_mod_inst_id[pn] &&
558
dst_mod_ip_port_id[pn]) {
559
mod->src_mod_op_port_id[id] = src_mod_op_port_id[pn];
560
mod->dst_mod_inst_id[id] = dst_mod_inst_id[pn];
561
mod->dst_mod_ip_port_id[id] = dst_mod_ip_port_id[pn];
562
id++;
563
mod->num_connections = id;
564
}
565
}
566
}
567
568
return mod;
569
}
570
571
static int audioreach_widget_load_module_common(struct snd_soc_component *component,
572
int index, struct snd_soc_dapm_widget *w,
573
struct snd_soc_tplg_dapm_widget *tplg_w)
574
{
575
struct q6apm *apm = dev_get_drvdata(component->dev);
576
struct audioreach_container *cont;
577
struct audioreach_sub_graph *sg;
578
struct audioreach_module *mod;
579
struct snd_soc_dobj *dobj;
580
581
sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv);
582
if (IS_ERR(sg))
583
return PTR_ERR(sg);
584
585
cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv);
586
if (IS_ERR(cont))
587
return PTR_ERR(cont);
588
589
mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w);
590
if (IS_ERR(mod))
591
return PTR_ERR(mod);
592
593
dobj = &w->dobj;
594
dobj->private = mod;
595
596
return 0;
597
}
598
599
static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component,
600
int index, struct snd_soc_dapm_widget *w,
601
struct snd_soc_tplg_dapm_widget *tplg_w)
602
{
603
struct snd_soc_tplg_vendor_value_elem *mod_elem;
604
struct snd_soc_tplg_vendor_array *mod_array;
605
struct audioreach_module *mod;
606
struct snd_soc_dobj *dobj;
607
int tkn_count = 0;
608
int ret;
609
610
ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
611
if (ret)
612
return ret;
613
614
dobj = &w->dobj;
615
mod = dobj->private;
616
mod_array = audioreach_get_module_array(&tplg_w->priv);
617
mod_elem = mod_array->value;
618
619
while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
620
switch (le32_to_cpu(mod_elem->token)) {
621
case AR_TKN_U32_MODULE_FMT_INTERLEAVE:
622
mod->interleave_type = le32_to_cpu(mod_elem->value);
623
break;
624
case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE:
625
mod->rate = le32_to_cpu(mod_elem->value);
626
break;
627
case AR_TKN_U32_MODULE_FMT_BIT_DEPTH:
628
mod->bit_depth = le32_to_cpu(mod_elem->value);
629
break;
630
default:
631
break;
632
}
633
tkn_count++;
634
mod_elem++;
635
}
636
637
return 0;
638
}
639
640
static int audioreach_widget_log_module_load(struct audioreach_module *mod,
641
struct snd_soc_tplg_vendor_array *mod_array)
642
{
643
struct snd_soc_tplg_vendor_value_elem *mod_elem;
644
int tkn_count = 0;
645
646
mod_elem = mod_array->value;
647
648
while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
649
switch (le32_to_cpu(mod_elem->token)) {
650
651
case AR_TKN_U32_MODULE_LOG_CODE:
652
mod->log_code = le32_to_cpu(mod_elem->value);
653
break;
654
case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID:
655
mod->log_tap_point_id = le32_to_cpu(mod_elem->value);
656
break;
657
case AR_TKN_U32_MODULE_LOG_MODE:
658
mod->log_mode = le32_to_cpu(mod_elem->value);
659
break;
660
default:
661
break;
662
}
663
tkn_count++;
664
mod_elem++;
665
}
666
667
return 0;
668
}
669
670
static int audioreach_widget_dma_module_load(struct audioreach_module *mod,
671
struct snd_soc_tplg_vendor_array *mod_array)
672
{
673
struct snd_soc_tplg_vendor_value_elem *mod_elem;
674
int tkn_count = 0;
675
676
mod_elem = mod_array->value;
677
678
while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
679
switch (le32_to_cpu(mod_elem->token)) {
680
case AR_TKN_U32_MODULE_HW_IF_IDX:
681
mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
682
break;
683
case AR_TKN_U32_MODULE_FMT_DATA:
684
mod->data_format = le32_to_cpu(mod_elem->value);
685
break;
686
case AR_TKN_U32_MODULE_HW_IF_TYPE:
687
mod->hw_interface_type = le32_to_cpu(mod_elem->value);
688
break;
689
default:
690
break;
691
}
692
tkn_count++;
693
mod_elem++;
694
}
695
696
return 0;
697
}
698
699
static int audioreach_widget_i2s_module_load(struct audioreach_module *mod,
700
struct snd_soc_tplg_vendor_array *mod_array)
701
{
702
struct snd_soc_tplg_vendor_value_elem *mod_elem;
703
int tkn_count = 0;
704
705
mod_elem = mod_array->value;
706
707
while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
708
switch (le32_to_cpu(mod_elem->token)) {
709
case AR_TKN_U32_MODULE_HW_IF_IDX:
710
mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
711
break;
712
case AR_TKN_U32_MODULE_FMT_DATA:
713
mod->data_format = le32_to_cpu(mod_elem->value);
714
break;
715
case AR_TKN_U32_MODULE_HW_IF_TYPE:
716
mod->hw_interface_type = le32_to_cpu(mod_elem->value);
717
break;
718
case AR_TKN_U32_MODULE_SD_LINE_IDX:
719
mod->sd_line_idx = le32_to_cpu(mod_elem->value);
720
break;
721
case AR_TKN_U32_MODULE_WS_SRC:
722
mod->ws_src = le32_to_cpu(mod_elem->value);
723
break;
724
default:
725
break;
726
}
727
tkn_count++;
728
mod_elem++;
729
}
730
731
return 0;
732
}
733
734
static int audioreach_widget_dp_module_load(struct audioreach_module *mod,
735
struct snd_soc_tplg_vendor_array *mod_array)
736
{
737
struct snd_soc_tplg_vendor_value_elem *mod_elem;
738
int tkn_count = 0;
739
740
mod_elem = mod_array->value;
741
742
while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
743
switch (le32_to_cpu(mod_elem->token)) {
744
case AR_TKN_U32_MODULE_FMT_DATA:
745
mod->data_format = le32_to_cpu(mod_elem->value);
746
break;
747
default:
748
break;
749
}
750
tkn_count++;
751
mod_elem++;
752
}
753
754
return 0;
755
}
756
757
static int audioreach_widget_load_buffer(struct snd_soc_component *component,
758
int index, struct snd_soc_dapm_widget *w,
759
struct snd_soc_tplg_dapm_widget *tplg_w)
760
{
761
struct snd_soc_tplg_vendor_array *mod_array;
762
struct audioreach_module *mod;
763
struct snd_soc_dobj *dobj;
764
int ret;
765
766
ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
767
if (ret)
768
return ret;
769
770
dobj = &w->dobj;
771
mod = dobj->private;
772
773
mod_array = audioreach_get_module_array(&tplg_w->priv);
774
775
switch (mod->module_id) {
776
case MODULE_ID_CODEC_DMA_SINK:
777
case MODULE_ID_CODEC_DMA_SOURCE:
778
audioreach_widget_dma_module_load(mod, mod_array);
779
break;
780
case MODULE_ID_DATA_LOGGING:
781
audioreach_widget_log_module_load(mod, mod_array);
782
break;
783
case MODULE_ID_I2S_SINK:
784
case MODULE_ID_I2S_SOURCE:
785
audioreach_widget_i2s_module_load(mod, mod_array);
786
break;
787
case MODULE_ID_DISPLAY_PORT_SINK:
788
audioreach_widget_dp_module_load(mod, mod_array);
789
break;
790
default:
791
return -EINVAL;
792
}
793
794
return 0;
795
}
796
797
static int audioreach_widget_load_mixer(struct snd_soc_component *component,
798
int index, struct snd_soc_dapm_widget *w,
799
struct snd_soc_tplg_dapm_widget *tplg_w)
800
{
801
struct snd_soc_tplg_vendor_value_elem *w_elem;
802
struct snd_soc_tplg_vendor_array *w_array;
803
struct snd_ar_control *scontrol;
804
struct q6apm *data = dev_get_drvdata(component->dev);
805
struct snd_soc_dobj *dobj;
806
int tkn_count = 0;
807
808
w_array = &tplg_w->priv.array[0];
809
810
scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
811
if (!scontrol)
812
return -ENOMEM;
813
814
scontrol->scomp = component;
815
dobj = &w->dobj;
816
dobj->private = scontrol;
817
818
w_elem = w_array->value;
819
while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) {
820
switch (le32_to_cpu(w_elem->token)) {
821
case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
822
scontrol->sgid = le32_to_cpu(w_elem->value);
823
break;
824
case AR_TKN_DAI_INDEX:
825
scontrol->graph_id = le32_to_cpu(w_elem->value);
826
break;
827
default: /* ignore other tokens */
828
break;
829
}
830
tkn_count++;
831
w_elem++;
832
}
833
834
scontrol->w = w;
835
list_add_tail(&scontrol->node, &data->widget_list);
836
837
return 0;
838
}
839
840
static int audioreach_pga_event(struct snd_soc_dapm_widget *w,
841
struct snd_kcontrol *kcontrol, int event)
842
843
{
844
struct snd_soc_dapm_context *dapm = w->dapm;
845
struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
846
struct audioreach_module *mod = w->dobj.private;
847
struct q6apm *apm = dev_get_drvdata(c->dev);
848
849
switch (event) {
850
case SND_SOC_DAPM_POST_PMU:
851
/* apply gain after power up of widget */
852
audioreach_gain_set_vol_ctrl(apm, mod, mod->gain);
853
break;
854
default:
855
break;
856
}
857
858
return 0;
859
}
860
861
static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = {
862
{ AR_PGA_DAPM_EVENT, audioreach_pga_event },
863
};
864
865
static int audioreach_widget_load_pga(struct snd_soc_component *component,
866
int index, struct snd_soc_dapm_widget *w,
867
struct snd_soc_tplg_dapm_widget *tplg_w)
868
{
869
struct audioreach_module *mod;
870
struct snd_soc_dobj *dobj;
871
int ret;
872
873
ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
874
if (ret)
875
return ret;
876
877
dobj = &w->dobj;
878
mod = dobj->private;
879
mod->gain = VOL_CTRL_DEFAULT_GAIN;
880
881
ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops,
882
ARRAY_SIZE(audioreach_widget_ops),
883
le16_to_cpu(tplg_w->event_type));
884
if (ret) {
885
dev_err(component->dev, "matching event handlers NOT found for %d\n",
886
le16_to_cpu(tplg_w->event_type));
887
return -EINVAL;
888
}
889
890
return 0;
891
}
892
893
static int audioreach_widget_ready(struct snd_soc_component *component,
894
int index, struct snd_soc_dapm_widget *w,
895
struct snd_soc_tplg_dapm_widget *tplg_w)
896
{
897
switch (w->id) {
898
case snd_soc_dapm_aif_in:
899
case snd_soc_dapm_aif_out:
900
audioreach_widget_load_buffer(component, index, w, tplg_w);
901
break;
902
case snd_soc_dapm_decoder:
903
case snd_soc_dapm_encoder:
904
case snd_soc_dapm_src:
905
audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w);
906
break;
907
case snd_soc_dapm_buffer:
908
audioreach_widget_load_buffer(component, index, w, tplg_w);
909
break;
910
case snd_soc_dapm_mixer:
911
return audioreach_widget_load_mixer(component, index, w, tplg_w);
912
case snd_soc_dapm_pga:
913
return audioreach_widget_load_pga(component, index, w, tplg_w);
914
case snd_soc_dapm_dai_link:
915
case snd_soc_dapm_scheduler:
916
case snd_soc_dapm_out_drv:
917
default:
918
dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id);
919
break;
920
}
921
922
return 0;
923
}
924
925
static int audioreach_widget_unload(struct snd_soc_component *scomp,
926
struct snd_soc_dobj *dobj)
927
{
928
struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj);
929
struct q6apm *apm = dev_get_drvdata(scomp->dev);
930
struct audioreach_container *cont;
931
struct audioreach_module *mod;
932
933
mod = dobj->private;
934
cont = mod->container;
935
936
if (w->id == snd_soc_dapm_mixer) {
937
/* virtual widget */
938
struct snd_ar_control *scontrol = dobj->private;
939
940
list_del(&scontrol->node);
941
kfree(scontrol);
942
return 0;
943
}
944
945
mutex_lock(&apm->lock);
946
idr_remove(&apm->modules_idr, mod->instance_id);
947
cont->num_modules--;
948
949
list_del(&mod->node);
950
kfree(mod);
951
/* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */
952
if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */
953
struct audioreach_sub_graph *sg = cont->sub_graph;
954
955
idr_remove(&apm->containers_idr, cont->container_id);
956
list_del(&cont->node);
957
sg->num_containers--;
958
kfree(cont);
959
/* check if there are no more containers in the sub graph and remove it */
960
if (list_empty(&sg->container_list)) {
961
struct audioreach_graph_info *info = sg->info;
962
963
idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id);
964
list_del(&sg->node);
965
info->num_sub_graphs--;
966
kfree(sg);
967
/* Check if there are no more sub-graphs left then remove graph info */
968
if (list_empty(&info->sg_list)) {
969
idr_remove(&apm->graph_info_idr, info->id);
970
kfree(info);
971
}
972
}
973
}
974
975
mutex_unlock(&apm->lock);
976
977
return 0;
978
}
979
980
static struct snd_ar_control *audioreach_find_widget(struct snd_soc_component *comp,
981
const char *name)
982
{
983
struct q6apm *apm = dev_get_drvdata(comp->dev);
984
struct snd_ar_control *control;
985
986
list_for_each_entry(control, &apm->widget_list, node) {
987
if (control->w && !strcmp(name, control->w->name))
988
return control;
989
}
990
991
return NULL;
992
}
993
994
static struct audioreach_module *audioreach_find_module(struct snd_soc_component *comp,
995
const char *name)
996
{
997
struct q6apm *apm = dev_get_drvdata(comp->dev);
998
struct audioreach_module *module;
999
int id;
1000
1001
idr_for_each_entry(&apm->modules_idr, module, id) {
1002
if (!strcmp(name, module->widget->name))
1003
return module;
1004
}
1005
1006
return NULL;
1007
}
1008
1009
static int audioreach_route_load(struct snd_soc_component *scomp, int index,
1010
struct snd_soc_dapm_route *route)
1011
{
1012
struct audioreach_module *src_module, *sink_module;
1013
struct snd_ar_control *control;
1014
struct snd_soc_dapm_widget *w;
1015
int i;
1016
1017
/* check if these are actual modules */
1018
src_module = audioreach_find_module(scomp, route->source);
1019
sink_module = audioreach_find_module(scomp, route->sink);
1020
1021
if (sink_module && !src_module) {
1022
control = audioreach_find_widget(scomp, route->source);
1023
if (control)
1024
control->module_instance_id = sink_module->instance_id;
1025
1026
} else if (!sink_module && src_module && route->control) {
1027
/* check if this is a virtual mixer */
1028
control = audioreach_find_widget(scomp, route->sink);
1029
if (!control || !control->w)
1030
return 0;
1031
1032
w = control->w;
1033
1034
for (i = 0; i < w->num_kcontrols; i++) {
1035
if (!strcmp(route->control, w->kcontrol_news[i].name)) {
1036
struct soc_mixer_control *sm;
1037
struct snd_soc_dobj *dobj;
1038
struct snd_ar_control *scontrol;
1039
1040
sm = (struct soc_mixer_control *)w->kcontrol_news[i].private_value;
1041
dobj = &sm->dobj;
1042
scontrol = dobj->private;
1043
scontrol->module_instance_id = src_module->instance_id;
1044
}
1045
}
1046
1047
}
1048
1049
return 0;
1050
}
1051
1052
static int audioreach_route_unload(struct snd_soc_component *scomp,
1053
struct snd_soc_dobj *dobj)
1054
{
1055
return 0;
1056
}
1057
1058
static int audioreach_tplg_complete(struct snd_soc_component *component)
1059
{
1060
/* TBD */
1061
return 0;
1062
}
1063
1064
/* DAI link - used for any driver specific init */
1065
static int audioreach_link_load(struct snd_soc_component *component, int index,
1066
struct snd_soc_dai_link *link,
1067
struct snd_soc_tplg_link_config *cfg)
1068
{
1069
link->nonatomic = true;
1070
link->dynamic = true;
1071
link->platforms->name = NULL;
1072
link->platforms->of_node = of_get_compatible_child(component->dev->of_node,
1073
"qcom,q6apm-dais");
1074
return 0;
1075
}
1076
1077
static void audioreach_connect_sub_graphs(struct q6apm *apm,
1078
struct snd_ar_control *m1,
1079
struct snd_ar_control *m2,
1080
bool connect)
1081
{
1082
struct audioreach_graph_info *info;
1083
1084
mutex_lock(&apm->lock);
1085
info = idr_find(&apm->graph_info_idr, m2->graph_id);
1086
mutex_unlock(&apm->lock);
1087
1088
if (connect) {
1089
info->src_mod_inst_id = m1->module_instance_id;
1090
info->src_mod_op_port_id = 1;
1091
info->dst_mod_inst_id = m2->module_instance_id;
1092
info->dst_mod_ip_port_id = 2;
1093
1094
} else {
1095
info->src_mod_inst_id = 0;
1096
info->src_mod_op_port_id = 0;
1097
info->dst_mod_inst_id = 0;
1098
info->dst_mod_ip_port_id = 0;
1099
}
1100
}
1101
1102
static bool audioreach_is_vmixer_connected(struct q6apm *apm,
1103
struct snd_ar_control *m1,
1104
struct snd_ar_control *m2)
1105
{
1106
struct audioreach_graph_info *info;
1107
1108
mutex_lock(&apm->lock);
1109
info = idr_find(&apm->graph_info_idr, m2->graph_id);
1110
mutex_unlock(&apm->lock);
1111
1112
if (info->dst_mod_inst_id == m2->module_instance_id &&
1113
info->src_mod_inst_id == m1->module_instance_id)
1114
return true;
1115
1116
return false;
1117
}
1118
1119
static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
1120
struct snd_ctl_elem_value *ucontrol)
1121
{
1122
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
1123
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
1124
struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1125
struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
1126
struct snd_ar_control *dapm_scontrol = dw->dobj.private;
1127
struct snd_ar_control *scontrol = mc->dobj.private;
1128
struct q6apm *data = dev_get_drvdata(c->dev);
1129
bool connected;
1130
1131
connected = audioreach_is_vmixer_connected(data, scontrol, dapm_scontrol);
1132
if (connected)
1133
ucontrol->value.integer.value[0] = 1;
1134
else
1135
ucontrol->value.integer.value[0] = 0;
1136
1137
return 0;
1138
}
1139
1140
static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol,
1141
struct snd_ctl_elem_value *ucontrol)
1142
{
1143
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
1144
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
1145
struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1146
struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
1147
struct snd_ar_control *dapm_scontrol = dw->dobj.private;
1148
struct snd_ar_control *scontrol = mc->dobj.private;
1149
struct q6apm *data = dev_get_drvdata(c->dev);
1150
1151
if (ucontrol->value.integer.value[0]) {
1152
audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, true);
1153
snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL);
1154
} else {
1155
audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, false);
1156
snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL);
1157
}
1158
return 0;
1159
}
1160
1161
static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
1162
struct snd_ctl_elem_value *ucontrol)
1163
{
1164
struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1165
struct audioreach_module *mod = dw->dobj.private;
1166
1167
ucontrol->value.integer.value[0] = mod->gain;
1168
1169
return 0;
1170
}
1171
1172
static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
1173
struct snd_ctl_elem_value *ucontrol)
1174
{
1175
struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1176
struct audioreach_module *mod = dw->dobj.private;
1177
1178
mod->gain = ucontrol->value.integer.value[0];
1179
1180
return 1;
1181
}
1182
1183
static int audioreach_control_load_mix(struct snd_soc_component *scomp,
1184
struct snd_ar_control *scontrol,
1185
struct snd_kcontrol_new *kc,
1186
struct snd_soc_tplg_ctl_hdr *hdr)
1187
{
1188
struct snd_soc_tplg_vendor_value_elem *c_elem;
1189
struct snd_soc_tplg_vendor_array *c_array;
1190
struct snd_soc_tplg_mixer_control *mc;
1191
int tkn_count = 0;
1192
1193
mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
1194
c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data;
1195
1196
c_elem = c_array->value;
1197
1198
while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) {
1199
switch (le32_to_cpu(c_elem->token)) {
1200
case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
1201
scontrol->sgid = le32_to_cpu(c_elem->value);
1202
break;
1203
case AR_TKN_DAI_INDEX:
1204
scontrol->graph_id = le32_to_cpu(c_elem->value);
1205
break;
1206
default:
1207
/* Ignore other tokens */
1208
break;
1209
}
1210
c_elem++;
1211
tkn_count++;
1212
}
1213
1214
return 0;
1215
}
1216
1217
static int audioreach_control_load(struct snd_soc_component *scomp, int index,
1218
struct snd_kcontrol_new *kc,
1219
struct snd_soc_tplg_ctl_hdr *hdr)
1220
{
1221
struct snd_ar_control *scontrol;
1222
struct soc_mixer_control *sm;
1223
struct snd_soc_dobj *dobj;
1224
int ret = 0;
1225
1226
scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
1227
if (!scontrol)
1228
return -ENOMEM;
1229
1230
scontrol->scomp = scomp;
1231
1232
switch (le32_to_cpu(hdr->ops.get)) {
1233
case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX:
1234
sm = (struct soc_mixer_control *)kc->private_value;
1235
dobj = &sm->dobj;
1236
ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr);
1237
break;
1238
case SND_SOC_AR_TPLG_VOL_CTL:
1239
sm = (struct soc_mixer_control *)kc->private_value;
1240
dobj = &sm->dobj;
1241
break;
1242
default:
1243
dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
1244
hdr->ops.get, hdr->ops.put, hdr->ops.info);
1245
kfree(scontrol);
1246
return -EINVAL;
1247
}
1248
1249
dobj->private = scontrol;
1250
return ret;
1251
}
1252
1253
static int audioreach_control_unload(struct snd_soc_component *scomp,
1254
struct snd_soc_dobj *dobj)
1255
{
1256
struct snd_ar_control *scontrol = dobj->private;
1257
1258
kfree(scontrol);
1259
1260
return 0;
1261
}
1262
1263
static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = {
1264
{SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer,
1265
audioreach_put_audio_mixer, snd_soc_info_volsw},
1266
{SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer,
1267
audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw},
1268
};
1269
1270
static const struct snd_soc_tplg_ops audioreach_tplg_ops = {
1271
.io_ops = audioreach_io_ops,
1272
.io_ops_count = ARRAY_SIZE(audioreach_io_ops),
1273
1274
.control_load = audioreach_control_load,
1275
.control_unload = audioreach_control_unload,
1276
1277
.widget_ready = audioreach_widget_ready,
1278
.widget_unload = audioreach_widget_unload,
1279
1280
.complete = audioreach_tplg_complete,
1281
.link_load = audioreach_link_load,
1282
1283
.dapm_route_load = audioreach_route_load,
1284
.dapm_route_unload = audioreach_route_unload,
1285
};
1286
1287
int audioreach_tplg_init(struct snd_soc_component *component)
1288
{
1289
struct snd_soc_card *card = component->card;
1290
struct device *dev = component->dev;
1291
const struct firmware *fw;
1292
int ret;
1293
1294
/* Inline with Qualcomm UCM configs and linux-firmware path */
1295
char *tplg_fw_name __free(kfree) = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin",
1296
card->driver_name,
1297
card->name);
1298
if (!tplg_fw_name)
1299
return -ENOMEM;
1300
1301
ret = request_firmware(&fw, tplg_fw_name, dev);
1302
if (ret < 0) {
1303
dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret);
1304
return ret;
1305
}
1306
1307
ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw);
1308
if (ret < 0) {
1309
if (ret != -EPROBE_DEFER)
1310
dev_err(dev, "tplg component load failed: %d\n", ret);
1311
}
1312
1313
release_firmware(fw);
1314
1315
return ret;
1316
}
1317
EXPORT_SYMBOL_GPL(audioreach_tplg_init);
1318
1319